@azure/identity 2.0.0-beta.4 → 2.0.1-alpha.20211025.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @azure/identity might be problematic. Click here for more details.
- package/CHANGELOG.md +215 -4
- package/README.md +78 -25
- package/dist/index.js +888 -477
- package/dist/index.js.map +1 -1
- package/dist-esm/src/client/identityClient.js +75 -62
- package/dist-esm/src/client/identityClient.js.map +1 -1
- package/dist-esm/src/credentials/authorizationCodeCredential.browser.js +1 -1
- package/dist-esm/src/credentials/authorizationCodeCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/authorizationCodeCredential.js +12 -74
- package/dist-esm/src/credentials/authorizationCodeCredential.js.map +1 -1
- package/dist-esm/src/credentials/azureApplicationCredential.browser.js +34 -0
- package/dist-esm/src/credentials/azureApplicationCredential.browser.js.map +1 -0
- package/dist-esm/src/credentials/azureApplicationCredential.js +36 -0
- package/dist-esm/src/credentials/azureApplicationCredential.js.map +1 -0
- package/dist-esm/src/credentials/azureCliCredential.browser.js +7 -0
- package/dist-esm/src/credentials/azureCliCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/azureCliCredential.js +10 -10
- package/dist-esm/src/credentials/azureCliCredential.js.map +1 -1
- package/dist-esm/src/credentials/azurePowerShellCredential.browser.js +3 -1
- package/dist-esm/src/credentials/azurePowerShellCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/azurePowerShellCredential.js +13 -13
- package/dist-esm/src/credentials/azurePowerShellCredential.js.map +1 -1
- package/dist-esm/src/credentials/chainedTokenCredential.js +3 -3
- package/dist-esm/src/credentials/chainedTokenCredential.js.map +1 -1
- package/dist-esm/src/credentials/clientCertificateCredential.browser.js +7 -0
- package/dist-esm/src/credentials/clientCertificateCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/clientCertificateCredential.js +19 -13
- package/dist-esm/src/credentials/clientCertificateCredential.js.map +1 -1
- package/dist-esm/src/credentials/clientCertificateCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/clientSecretCredential.browser.js +17 -19
- package/dist-esm/src/credentials/clientSecretCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/clientSecretCredential.js +3 -0
- package/dist-esm/src/credentials/clientSecretCredential.js.map +1 -1
- package/dist-esm/src/credentials/clientSecretCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/credentialPersistenceOptions.js.map +1 -1
- package/dist-esm/src/credentials/defaultAzureCredential.browser.js +1 -1
- package/dist-esm/src/credentials/defaultAzureCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/defaultAzureCredential.js +22 -21
- package/dist-esm/src/credentials/defaultAzureCredential.js.map +1 -1
- package/dist-esm/src/credentials/deviceCodeCredential.browser.js +7 -0
- package/dist-esm/src/credentials/deviceCodeCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/deviceCodeCredential.js +14 -0
- package/dist-esm/src/credentials/deviceCodeCredential.js.map +1 -1
- package/dist-esm/src/credentials/deviceCodeCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/environmentCredential.browser.js +7 -0
- package/dist-esm/src/credentials/environmentCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/environmentCredential.js +5 -21
- package/dist-esm/src/credentials/environmentCredential.js.map +1 -1
- package/dist-esm/src/credentials/interactiveBrowserCredential.browser.js +7 -7
- package/dist-esm/src/credentials/interactiveBrowserCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/interactiveBrowserCredential.js +7 -7
- package/dist-esm/src/credentials/interactiveBrowserCredential.js.map +1 -1
- package/dist-esm/src/credentials/interactiveBrowserCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js +31 -12
- package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js +45 -23
- package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js +29 -13
- package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/constants.js +2 -1
- package/dist-esm/src/credentials/managedIdentityCredential/constants.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js +36 -11
- package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js +69 -47
- package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/index.js +19 -17
- package/dist-esm/src/credentials/managedIdentityCredential/index.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/models.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js +82 -0
- package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js.map +1 -0
- package/dist-esm/src/credentials/managedIdentityCredential/utils.js +16 -4
- package/dist-esm/src/credentials/managedIdentityCredential/utils.js.map +1 -1
- package/dist-esm/src/credentials/onBehalfOfCredential.browser.js +23 -0
- package/dist-esm/src/credentials/onBehalfOfCredential.browser.js.map +1 -0
- package/dist-esm/src/credentials/onBehalfOfCredential.js +57 -0
- package/dist-esm/src/credentials/onBehalfOfCredential.js.map +1 -0
- package/dist-esm/src/credentials/{visualStudioCodeCredentialExtension.js → onBehalfOfCredentialOptions.js} +1 -1
- package/dist-esm/src/credentials/onBehalfOfCredentialOptions.js.map +1 -0
- package/dist-esm/src/credentials/usernamePasswordCredential.browser.js +17 -19
- package/dist-esm/src/credentials/usernamePasswordCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/usernamePasswordCredential.js +3 -2
- package/dist-esm/src/credentials/usernamePasswordCredential.js.map +1 -1
- package/dist-esm/src/credentials/visualStudioCodeCredential.browser.js +7 -1
- package/dist-esm/src/credentials/visualStudioCodeCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/visualStudioCodeCredential.js +16 -8
- package/dist-esm/src/credentials/visualStudioCodeCredential.js.map +1 -1
- package/dist-esm/src/credentials/visualStudioCodeCredentialPlugin.js +4 -0
- package/dist-esm/src/credentials/visualStudioCodeCredentialPlugin.js.map +1 -0
- package/dist-esm/src/{client/errors.js → errors.js} +16 -1
- package/dist-esm/src/errors.js.map +1 -0
- package/dist-esm/src/index.js +3 -4
- package/dist-esm/src/index.js.map +1 -1
- package/dist-esm/src/msal/browserFlows/browserCommon.js +8 -7
- package/dist-esm/src/msal/browserFlows/browserCommon.js.map +1 -1
- package/dist-esm/src/msal/browserFlows/msalAuthCode.js +12 -4
- package/dist-esm/src/msal/browserFlows/msalAuthCode.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js +41 -0
- package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js.map +1 -0
- package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js +49 -29
- package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalClientSecret.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js +56 -0
- package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js.map +1 -0
- package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js +2 -2
- package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/nodeCommon.js +32 -13
- package/dist-esm/src/msal/nodeFlows/nodeCommon.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/tokenCachePersistenceOptions.js.map +1 -1
- package/dist-esm/src/msal/utils.js +15 -8
- package/dist-esm/src/msal/utils.js.map +1 -1
- package/dist-esm/src/plugins/consumer.browser.js +7 -0
- package/dist-esm/src/plugins/consumer.browser.js.map +1 -0
- package/dist-esm/src/{extensions → plugins}/consumer.js +12 -12
- package/dist-esm/src/plugins/consumer.js.map +1 -0
- package/dist-esm/src/{extensions → plugins}/provider.js +0 -0
- package/dist-esm/src/plugins/provider.js.map +1 -0
- package/dist-esm/src/util/tracing.js +2 -2
- package/dist-esm/src/util/tracing.js.map +1 -1
- package/dist-esm/src/util/validateMultiTenant.browser.js +22 -0
- package/dist-esm/src/util/validateMultiTenant.browser.js.map +1 -0
- package/dist-esm/src/util/validateMultiTenant.js +17 -12
- package/dist-esm/src/util/validateMultiTenant.js.map +1 -1
- package/package.json +38 -21
- package/types/identity.d.ts +250 -225
- package/dist-esm/src/client/errors.js.map +0 -1
- package/dist-esm/src/credentials/visualStudioCodeCredentialExtension.js.map +0 -1
- package/dist-esm/src/extensions/consumer.browser.js +0 -7
- package/dist-esm/src/extensions/consumer.browser.js.map +0 -1
- package/dist-esm/src/extensions/consumer.js.map +0 -1
- package/dist-esm/src/extensions/provider.js.map +0 -1
- package/dist-esm/src/msal/errors.js +0 -22
- package/dist-esm/src/msal/errors.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -5,11 +5,12 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
|
6
6
|
|
|
7
7
|
var msalNode = require('@azure/msal-node');
|
|
8
|
-
var
|
|
9
|
-
var coreHttp = require('@azure/core-http');
|
|
8
|
+
var coreClient = require('@azure/core-client');
|
|
10
9
|
var coreTracing = require('@azure/core-tracing');
|
|
10
|
+
var coreUtil = require('@azure/core-util');
|
|
11
|
+
var coreRestPipeline = require('@azure/core-rest-pipeline');
|
|
11
12
|
var abortController = require('@azure/abort-controller');
|
|
12
|
-
var logger$
|
|
13
|
+
var logger$k = require('@azure/logger');
|
|
13
14
|
var msalCommon = require('@azure/msal-common');
|
|
14
15
|
var uuid = require('uuid');
|
|
15
16
|
var fs = require('fs');
|
|
@@ -17,7 +18,10 @@ var fs__default = _interopDefault(fs);
|
|
|
17
18
|
var os = _interopDefault(require('os'));
|
|
18
19
|
var path = _interopDefault(require('path'));
|
|
19
20
|
var child_process = require('child_process');
|
|
21
|
+
var child_process__default = _interopDefault(child_process);
|
|
20
22
|
var crypto = require('crypto');
|
|
23
|
+
var util = require('util');
|
|
24
|
+
var https = _interopDefault(require('https'));
|
|
21
25
|
var http = _interopDefault(require('http'));
|
|
22
26
|
var open = _interopDefault(require('open'));
|
|
23
27
|
var stoppable = _interopDefault(require('stoppable'));
|
|
@@ -147,7 +151,7 @@ const AggregateAuthenticationErrorName = "AggregateAuthenticationError";
|
|
|
147
151
|
class AggregateAuthenticationError extends Error {
|
|
148
152
|
constructor(errors, errorMessage) {
|
|
149
153
|
const errorDetail = errors.join("\n");
|
|
150
|
-
super(`${errorMessage}\n
|
|
154
|
+
super(`${errorMessage}\n${errorDetail}`);
|
|
151
155
|
this.errors = errors;
|
|
152
156
|
// Ensure that this type reports the correct name
|
|
153
157
|
this.name = AggregateAuthenticationErrorName;
|
|
@@ -163,6 +167,21 @@ function convertOAuthErrorResponseToErrorResponse(errorBody) {
|
|
|
163
167
|
traceId: errorBody.trace_id
|
|
164
168
|
};
|
|
165
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Error used to enforce authentication after trying to retrieve a token silently.
|
|
172
|
+
*/
|
|
173
|
+
class AuthenticationRequiredError extends Error {
|
|
174
|
+
constructor(
|
|
175
|
+
/**
|
|
176
|
+
* Optional parameters. A message can be specified. The {@link GetTokenOptions} of the request can also be specified to more easily associate the error with the received parameters.
|
|
177
|
+
*/
|
|
178
|
+
options) {
|
|
179
|
+
super(options.message);
|
|
180
|
+
this.scopes = options.scopes;
|
|
181
|
+
this.getTokenOptions = options.getTokenOptions;
|
|
182
|
+
this.name = "AuthenticationRequiredError";
|
|
183
|
+
}
|
|
184
|
+
}
|
|
166
185
|
|
|
167
186
|
// Copyright (c) Microsoft Corporation.
|
|
168
187
|
// Licensed under the MIT license.
|
|
@@ -181,7 +200,7 @@ function getIdentityTokenEndpointSuffix(tenantId) {
|
|
|
181
200
|
* @internal
|
|
182
201
|
*/
|
|
183
202
|
const createSpan = coreTracing.createSpanFunction({
|
|
184
|
-
packagePrefix: "
|
|
203
|
+
packagePrefix: "",
|
|
185
204
|
namespace: "Microsoft.AAD"
|
|
186
205
|
});
|
|
187
206
|
/**
|
|
@@ -189,7 +208,7 @@ const createSpan = coreTracing.createSpanFunction({
|
|
|
189
208
|
* Traces an operation and properly handles reporting start, end and errors for a given span
|
|
190
209
|
*
|
|
191
210
|
* @param operationName - Name of a method in the TClient type
|
|
192
|
-
* @param options - An options class, typically derived from \@azure/core-
|
|
211
|
+
* @param options - An options class, typically derived from \@azure/core-rest-pipeline/RequestOptionsBase
|
|
193
212
|
* @param fn - The function to call with an options class that properly propagates the span context
|
|
194
213
|
*
|
|
195
214
|
* @internal
|
|
@@ -222,7 +241,7 @@ async function trace(operationName, options, fn, createSpanFn = createSpan) {
|
|
|
222
241
|
/**
|
|
223
242
|
* The AzureLogger used for all clients within the identity package
|
|
224
243
|
*/
|
|
225
|
-
const logger = logger$
|
|
244
|
+
const logger = logger$k.createClientLogger("identity");
|
|
226
245
|
/**
|
|
227
246
|
* Separates a list of environment variable names into a plain object with two arrays: an array of missing environment variables and another array with assigned environment variables.
|
|
228
247
|
* @param supportedEnvVars - List of environment variable names
|
|
@@ -296,8 +315,8 @@ const noCorrelationId = "noCorrelationId";
|
|
|
296
315
|
function getIdentityClientAuthorityHost(options) {
|
|
297
316
|
// The authorityHost can come from options or from the AZURE_AUTHORITY_HOST environment variable.
|
|
298
317
|
let authorityHost = options === null || options === void 0 ? void 0 : options.authorityHost;
|
|
299
|
-
// The AZURE_AUTHORITY_HOST environment variable can only be provided in
|
|
300
|
-
if (
|
|
318
|
+
// The AZURE_AUTHORITY_HOST environment variable can only be provided in Node.js.
|
|
319
|
+
if (coreUtil.isNode) {
|
|
301
320
|
authorityHost = authorityHost !== null && authorityHost !== void 0 ? authorityHost : process.env.AZURE_AUTHORITY_HOST;
|
|
302
321
|
}
|
|
303
322
|
// If the authorityHost is not provided, we use the default one from the public cloud: https://login.microsoftonline.com
|
|
@@ -310,51 +329,53 @@ function getIdentityClientAuthorityHost(options) {
|
|
|
310
329
|
* by calling to the `abortRequests()` method.
|
|
311
330
|
*
|
|
312
331
|
*/
|
|
313
|
-
class IdentityClient extends
|
|
332
|
+
class IdentityClient extends coreClient.ServiceClient {
|
|
314
333
|
constructor(options) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if (!
|
|
334
|
+
var _a;
|
|
335
|
+
const packageDetails = `azsdk-js-identity/2.0.1`;
|
|
336
|
+
const userAgentPrefix = ((_a = options === null || options === void 0 ? void 0 : options.userAgentOptions) === null || _a === void 0 ? void 0 : _a.userAgentPrefix)
|
|
337
|
+
? `${options.userAgentOptions.userAgentPrefix} ${packageDetails}`
|
|
338
|
+
: `${packageDetails}`;
|
|
339
|
+
const baseUri = getIdentityClientAuthorityHost(options);
|
|
340
|
+
if (!baseUri.startsWith("https:")) {
|
|
322
341
|
throw new Error("The authorityHost address must use the 'https' protocol.");
|
|
323
342
|
}
|
|
343
|
+
super(Object.assign(Object.assign({ requestContentType: "application/json; charset=utf-8" }, options), { userAgentOptions: {
|
|
344
|
+
userAgentPrefix
|
|
345
|
+
}, baseUri }));
|
|
346
|
+
this.authorityHost = baseUri;
|
|
324
347
|
this.abortControllers = new Map();
|
|
325
348
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
return webResource;
|
|
330
|
-
}
|
|
331
|
-
async sendTokenRequest(webResource, expiresOnParser) {
|
|
332
|
-
logger.info(`IdentityClient: sending token request to [${webResource.url}]`);
|
|
333
|
-
const response = await this.sendRequest(webResource);
|
|
349
|
+
async sendTokenRequest(request, expiresOnParser) {
|
|
350
|
+
logger.info(`IdentityClient: sending token request to [${request.url}]`);
|
|
351
|
+
const response = await this.sendRequest(request);
|
|
334
352
|
expiresOnParser =
|
|
335
353
|
expiresOnParser ||
|
|
336
354
|
((responseBody) => {
|
|
337
355
|
return Date.now() + responseBody.expires_in * 1000;
|
|
338
356
|
});
|
|
339
|
-
if (response.status === 200 || response.status === 201) {
|
|
357
|
+
if (response.bodyAsText && (response.status === 200 || response.status === 201)) {
|
|
358
|
+
const parsedBody = JSON.parse(response.bodyAsText);
|
|
359
|
+
if (!parsedBody.access_token) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
340
362
|
const token = {
|
|
341
363
|
accessToken: {
|
|
342
|
-
token:
|
|
343
|
-
expiresOnTimestamp: expiresOnParser(
|
|
364
|
+
token: parsedBody.access_token,
|
|
365
|
+
expiresOnTimestamp: expiresOnParser(parsedBody)
|
|
344
366
|
},
|
|
345
|
-
refreshToken:
|
|
367
|
+
refreshToken: parsedBody.refresh_token
|
|
346
368
|
};
|
|
347
|
-
logger.info(`IdentityClient: [${
|
|
369
|
+
logger.info(`IdentityClient: [${request.url}] token acquired, expires on ${token.accessToken.expiresOnTimestamp}`);
|
|
348
370
|
return token;
|
|
349
371
|
}
|
|
350
372
|
else {
|
|
351
|
-
const error = new AuthenticationError(response.status, response.
|
|
373
|
+
const error = new AuthenticationError(response.status, response.bodyAsText);
|
|
352
374
|
logger.warning(`IdentityClient: authentication error. HTTP status: ${response.status}, ${error.errorResponse.errorDescription}`);
|
|
353
375
|
throw error;
|
|
354
376
|
}
|
|
355
377
|
}
|
|
356
378
|
async refreshAccessToken(tenantId, clientId, scopes, refreshToken, clientSecret, expiresOnParser, options) {
|
|
357
|
-
var _a, _b;
|
|
358
379
|
if (refreshToken === undefined) {
|
|
359
380
|
return null;
|
|
360
381
|
}
|
|
@@ -369,23 +390,21 @@ class IdentityClient extends coreHttp.ServiceClient {
|
|
|
369
390
|
if (clientSecret !== undefined) {
|
|
370
391
|
refreshParams.client_secret = clientSecret;
|
|
371
392
|
}
|
|
393
|
+
const query = new URLSearchParams(refreshParams);
|
|
372
394
|
try {
|
|
373
395
|
const urlSuffix = getIdentityTokenEndpointSuffix(tenantId);
|
|
374
|
-
const
|
|
396
|
+
const request = coreRestPipeline.createPipelineRequest({
|
|
375
397
|
url: `${this.authorityHost}/${tenantId}/${urlSuffix}`,
|
|
376
398
|
method: "POST",
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
headers: {
|
|
399
|
+
body: query.toString(),
|
|
400
|
+
abortSignal: options && options.abortSignal,
|
|
401
|
+
headers: coreRestPipeline.createHttpHeaders({
|
|
381
402
|
Accept: "application/json",
|
|
382
403
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
383
|
-
},
|
|
384
|
-
|
|
385
|
-
tracingContext: (_b = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _b === void 0 ? void 0 : _b.tracingContext,
|
|
386
|
-
abortSignal: options && options.abortSignal
|
|
404
|
+
}),
|
|
405
|
+
tracingOptions: updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions
|
|
387
406
|
});
|
|
388
|
-
const response = await this.sendTokenRequest(
|
|
407
|
+
const response = await this.sendTokenRequest(request, expiresOnParser);
|
|
389
408
|
logger.info(`IdentityClient: refreshed token for client ID: ${clientId}`);
|
|
390
409
|
return response;
|
|
391
410
|
}
|
|
@@ -419,13 +438,19 @@ class IdentityClient extends coreHttp.ServiceClient {
|
|
|
419
438
|
// since MSAL doesn't allow us to pass options all the way through.
|
|
420
439
|
generateAbortSignal(correlationId) {
|
|
421
440
|
const controller = new abortController.AbortController();
|
|
422
|
-
const
|
|
423
|
-
const controllers = this.abortControllers.get(key) || [];
|
|
441
|
+
const controllers = this.abortControllers.get(correlationId) || [];
|
|
424
442
|
controllers.push(controller);
|
|
425
|
-
this.abortControllers.set(
|
|
443
|
+
this.abortControllers.set(correlationId, controllers);
|
|
444
|
+
const existingOnAbort = controller.signal.onabort;
|
|
445
|
+
controller.signal.onabort = (...params) => {
|
|
446
|
+
this.abortControllers.set(correlationId, undefined);
|
|
447
|
+
if (existingOnAbort) {
|
|
448
|
+
existingOnAbort(...params);
|
|
449
|
+
}
|
|
450
|
+
};
|
|
426
451
|
return controller.signal;
|
|
427
452
|
}
|
|
428
|
-
abortRequests(correlationId
|
|
453
|
+
abortRequests(correlationId) {
|
|
429
454
|
const key = correlationId || noCorrelationId;
|
|
430
455
|
const controllers = [
|
|
431
456
|
...(this.abortControllers.get(key) || []),
|
|
@@ -439,37 +464,43 @@ class IdentityClient extends coreHttp.ServiceClient {
|
|
|
439
464
|
controller.abort();
|
|
440
465
|
}
|
|
441
466
|
this.abortControllers.set(key, undefined);
|
|
442
|
-
this.abortControllers.set(noCorrelationId, undefined);
|
|
443
467
|
}
|
|
444
468
|
getCorrelationId(options) {
|
|
445
469
|
var _a;
|
|
446
470
|
const parameter = (_a = options === null || options === void 0 ? void 0 : options.body) === null || _a === void 0 ? void 0 : _a.split("&").map((part) => part.split("=")).find(([key]) => key === "client-request-id");
|
|
447
|
-
return parameter && parameter.length ? parameter[1] : noCorrelationId;
|
|
471
|
+
return parameter && parameter.length ? parameter[1] || noCorrelationId : noCorrelationId;
|
|
448
472
|
}
|
|
449
473
|
// The MSAL network module methods follow
|
|
450
|
-
sendGetRequestAsync(url, options) {
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
headers: response.headers.rawHeaders(),
|
|
458
|
-
status: response.status
|
|
459
|
-
};
|
|
474
|
+
async sendGetRequestAsync(url, options) {
|
|
475
|
+
const request = coreRestPipeline.createPipelineRequest({
|
|
476
|
+
url,
|
|
477
|
+
method: "GET",
|
|
478
|
+
body: options === null || options === void 0 ? void 0 : options.body,
|
|
479
|
+
headers: coreRestPipeline.createHttpHeaders(options === null || options === void 0 ? void 0 : options.headers),
|
|
480
|
+
abortSignal: this.generateAbortSignal(noCorrelationId)
|
|
460
481
|
});
|
|
482
|
+
const response = await this.sendRequest(request);
|
|
483
|
+
return {
|
|
484
|
+
body: response.bodyAsText ? JSON.parse(response.bodyAsText) : undefined,
|
|
485
|
+
headers: response.headers.toJSON(),
|
|
486
|
+
status: response.status
|
|
487
|
+
};
|
|
461
488
|
}
|
|
462
|
-
sendPostRequestAsync(url, options) {
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
status: response.status
|
|
471
|
-
};
|
|
489
|
+
async sendPostRequestAsync(url, options) {
|
|
490
|
+
const request = coreRestPipeline.createPipelineRequest({
|
|
491
|
+
url,
|
|
492
|
+
method: "POST",
|
|
493
|
+
body: options === null || options === void 0 ? void 0 : options.body,
|
|
494
|
+
headers: coreRestPipeline.createHttpHeaders(options === null || options === void 0 ? void 0 : options.headers),
|
|
495
|
+
// MSAL doesn't send the correlation ID on the get requests.
|
|
496
|
+
abortSignal: this.generateAbortSignal(this.getCorrelationId(options))
|
|
472
497
|
});
|
|
498
|
+
const response = await this.sendRequest(request);
|
|
499
|
+
return {
|
|
500
|
+
body: response.bodyAsText ? JSON.parse(response.bodyAsText) : undefined,
|
|
501
|
+
headers: response.headers.toJSON(),
|
|
502
|
+
status: response.status
|
|
503
|
+
};
|
|
473
504
|
}
|
|
474
505
|
}
|
|
475
506
|
|
|
@@ -497,28 +528,6 @@ function resolveTenantId(logger, tenantId, clientId) {
|
|
|
497
528
|
return "organizations";
|
|
498
529
|
}
|
|
499
530
|
|
|
500
|
-
// Copyright (c) Microsoft Corporation.
|
|
501
|
-
// Licensed under the MIT license.
|
|
502
|
-
/**
|
|
503
|
-
* Error used to enforce authentication after trying to retrieve a token silently.
|
|
504
|
-
*/
|
|
505
|
-
class AuthenticationRequiredError extends Error {
|
|
506
|
-
constructor(
|
|
507
|
-
/**
|
|
508
|
-
* The list of scopes for which the token will have access.
|
|
509
|
-
*/
|
|
510
|
-
scopes,
|
|
511
|
-
/**
|
|
512
|
-
* The options used to configure the getToken request.
|
|
513
|
-
*/
|
|
514
|
-
getTokenOptions = {}, message) {
|
|
515
|
-
super(message);
|
|
516
|
-
this.scopes = scopes;
|
|
517
|
-
this.getTokenOptions = getTokenOptions;
|
|
518
|
-
this.name = "AuthenticationRequiredError";
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
531
|
// Copyright (c) Microsoft Corporation.
|
|
523
532
|
/**
|
|
524
533
|
* Latest AuthenticationRecord version
|
|
@@ -532,7 +541,11 @@ const LatestAuthenticationRecordVersion = "1.0";
|
|
|
532
541
|
function ensureValidMsalToken(scopes, logger, msalToken, getTokenOptions) {
|
|
533
542
|
const error = (message) => {
|
|
534
543
|
logger.getToken.info(message);
|
|
535
|
-
return new AuthenticationRequiredError(
|
|
544
|
+
return new AuthenticationRequiredError({
|
|
545
|
+
scopes: Array.isArray(scopes) ? scopes : [scopes],
|
|
546
|
+
getTokenOptions,
|
|
547
|
+
message
|
|
548
|
+
});
|
|
536
549
|
};
|
|
537
550
|
if (!msalToken) {
|
|
538
551
|
throw error("No response");
|
|
@@ -548,7 +561,10 @@ function ensureValidMsalToken(scopes, logger, msalToken, getTokenOptions) {
|
|
|
548
561
|
* Generates a valid authority by combining a host with a tenantId.
|
|
549
562
|
* @internal
|
|
550
563
|
*/
|
|
551
|
-
function getAuthority(tenantId, host
|
|
564
|
+
function getAuthority(tenantId, host) {
|
|
565
|
+
if (!host) {
|
|
566
|
+
host = DefaultAuthorityHost;
|
|
567
|
+
}
|
|
552
568
|
if (host.endsWith("/")) {
|
|
553
569
|
return host + tenantId;
|
|
554
570
|
}
|
|
@@ -558,8 +574,9 @@ function getAuthority(tenantId, host = DefaultAuthorityHost) {
|
|
|
558
574
|
}
|
|
559
575
|
/**
|
|
560
576
|
* Generates the known authorities.
|
|
561
|
-
* If the
|
|
562
|
-
*
|
|
577
|
+
* If the Tenant Id is `adfs`, the authority can't be validated since the format won't match the expected one.
|
|
578
|
+
* For that reason, we have to force MSAL to disable validating the authority
|
|
579
|
+
* by sending it within the known authorities in the MSAL configuration.
|
|
563
580
|
* @internal
|
|
564
581
|
*/
|
|
565
582
|
function getKnownAuthorities(tenantId, authorityHost) {
|
|
@@ -573,7 +590,7 @@ function getKnownAuthorities(tenantId, authorityHost) {
|
|
|
573
590
|
* @param logger - The logger of the credential.
|
|
574
591
|
* @internal
|
|
575
592
|
*/
|
|
576
|
-
const defaultLoggerCallback = (logger, platform =
|
|
593
|
+
const defaultLoggerCallback = (logger, platform = coreUtil.isNode ? "Node" : "Browser") => (level, message, containsPii) => {
|
|
577
594
|
if (containsPii) {
|
|
578
595
|
return;
|
|
579
596
|
}
|
|
@@ -656,7 +673,7 @@ class MsalBaseUtilities {
|
|
|
656
673
|
error.name === "AbortError") {
|
|
657
674
|
return error;
|
|
658
675
|
}
|
|
659
|
-
return new AuthenticationRequiredError(scopes, getTokenOptions, error.message);
|
|
676
|
+
return new AuthenticationRequiredError({ scopes, getTokenOptions, message: error.message });
|
|
660
677
|
}
|
|
661
678
|
}
|
|
662
679
|
// transformations.ts
|
|
@@ -720,6 +737,40 @@ function deserializeAuthenticationRecord(serializedRecord) {
|
|
|
720
737
|
}
|
|
721
738
|
|
|
722
739
|
// Copyright (c) Microsoft Corporation.
|
|
740
|
+
// Licensed under the MIT license.
|
|
741
|
+
/**
|
|
742
|
+
* @internal
|
|
743
|
+
*/
|
|
744
|
+
const multiTenantDisabledErrorMessage = "A getToken request was attempted with a tenant different than the tenant configured at the initialization of the credential, but multi-tenant authentication has been disabled by the environment variable AZURE_IDENTITY_DISABLE_MULTITENANTAUTH.";
|
|
745
|
+
/**
|
|
746
|
+
* @internal
|
|
747
|
+
*/
|
|
748
|
+
const multiTenantADFSErrorMessage = "A new tenant Id can't be assigned through the GetTokenOptions when a credential has been originally configured to use the tenant `adfs`.";
|
|
749
|
+
/**
|
|
750
|
+
* Of getToken contains a tenantId, this functions allows picking this tenantId as the appropriate for authentication,
|
|
751
|
+
* unless multitenant authentication has been disabled through the AZURE_IDENTITY_DISABLE_MULTITENANTAUTH (on Node.js),
|
|
752
|
+
* or unless the original tenant Id is `adfs`.
|
|
753
|
+
* @internal
|
|
754
|
+
*/
|
|
755
|
+
function processMultiTenantRequest(tenantId, getTokenOptions) {
|
|
756
|
+
if (!(getTokenOptions === null || getTokenOptions === void 0 ? void 0 : getTokenOptions.tenantId)) {
|
|
757
|
+
return tenantId;
|
|
758
|
+
}
|
|
759
|
+
if (process.env.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH) {
|
|
760
|
+
throw new Error(multiTenantDisabledErrorMessage);
|
|
761
|
+
}
|
|
762
|
+
if (tenantId === "adfs") {
|
|
763
|
+
throw new Error(multiTenantADFSErrorMessage);
|
|
764
|
+
}
|
|
765
|
+
return getTokenOptions === null || getTokenOptions === void 0 ? void 0 : getTokenOptions.tenantId;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// Copyright (c) Microsoft Corporation.
|
|
769
|
+
// Licensed under the MIT license.
|
|
770
|
+
/**
|
|
771
|
+
* Helps specify a regional authority, or "AutoDiscoverRegion" to auto-detect the region.
|
|
772
|
+
*/
|
|
773
|
+
var RegionalAuthority;
|
|
723
774
|
(function (RegionalAuthority) {
|
|
724
775
|
/** Instructs MSAL to attempt to discover the region */
|
|
725
776
|
RegionalAuthority["AutoDiscoverRegion"] = "AutoDiscoverRegion";
|
|
@@ -827,31 +878,7 @@ function deserializeAuthenticationRecord(serializedRecord) {
|
|
|
827
878
|
RegionalAuthority["GovernmentUSDodEast"] = "usdodeast";
|
|
828
879
|
/** Uses the {@link RegionalAuthority} for the Azure 'usdodcentral' region. */
|
|
829
880
|
RegionalAuthority["GovernmentUSDodCentral"] = "usdodcentral";
|
|
830
|
-
})(
|
|
831
|
-
|
|
832
|
-
// Copyright (c) Microsoft Corporation.
|
|
833
|
-
// Licensed under the MIT license.
|
|
834
|
-
/**
|
|
835
|
-
* @internal
|
|
836
|
-
*/
|
|
837
|
-
const multiTenantErrorMessage = "A getToken request was attempted with a tenant different than the tenant configured at the initialization of the credential, but multi-tenant authentication was not enabled in this credential instance.";
|
|
838
|
-
/**
|
|
839
|
-
* Verifies whether locally assigned tenants are equal to tenants received through getToken.
|
|
840
|
-
* Returns the appropriate tenant.
|
|
841
|
-
* @internal
|
|
842
|
-
*/
|
|
843
|
-
function processMultiTenantRequest(tenantId, allowMultiTenantAuthentication, getTokenOptions) {
|
|
844
|
-
if (!allowMultiTenantAuthentication &&
|
|
845
|
-
(getTokenOptions === null || getTokenOptions === void 0 ? void 0 : getTokenOptions.tenantId) &&
|
|
846
|
-
tenantId &&
|
|
847
|
-
getTokenOptions.tenantId !== tenantId) {
|
|
848
|
-
throw new Error(multiTenantErrorMessage);
|
|
849
|
-
}
|
|
850
|
-
if (allowMultiTenantAuthentication && (getTokenOptions === null || getTokenOptions === void 0 ? void 0 : getTokenOptions.tenantId)) {
|
|
851
|
-
return getTokenOptions.tenantId;
|
|
852
|
-
}
|
|
853
|
-
return tenantId;
|
|
854
|
-
}
|
|
881
|
+
})(RegionalAuthority || (RegionalAuthority = {}));
|
|
855
882
|
|
|
856
883
|
// Copyright (c) Microsoft Corporation.
|
|
857
884
|
/**
|
|
@@ -869,7 +896,7 @@ const msalNodeFlowCacheControl = {
|
|
|
869
896
|
}
|
|
870
897
|
};
|
|
871
898
|
/**
|
|
872
|
-
* MSAL partial base client for
|
|
899
|
+
* MSAL partial base client for Node.js.
|
|
873
900
|
*
|
|
874
901
|
* It completes the input configuration with some default values.
|
|
875
902
|
* It also provides with utility protected methods that can be used from any of the clients,
|
|
@@ -884,22 +911,26 @@ class MsalNode extends MsalBaseUtilities {
|
|
|
884
911
|
this.requiresConfidential = false;
|
|
885
912
|
this.msalConfig = this.defaultNodeMsalConfig(options);
|
|
886
913
|
this.tenantId = resolveTenantId(options.logger, options.tenantId, options.clientId);
|
|
887
|
-
this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
|
|
888
914
|
this.clientId = this.msalConfig.auth.clientId;
|
|
889
915
|
// If persistence has been configured
|
|
890
916
|
if (persistenceProvider !== undefined && ((_a = options.tokenCachePersistenceOptions) === null || _a === void 0 ? void 0 : _a.enabled)) {
|
|
891
917
|
this.createCachePlugin = () => persistenceProvider(options.tokenCachePersistenceOptions);
|
|
892
918
|
}
|
|
893
919
|
else if ((_b = options.tokenCachePersistenceOptions) === null || _b === void 0 ? void 0 : _b.enabled) {
|
|
894
|
-
throw new Error(
|
|
920
|
+
throw new Error([
|
|
921
|
+
"Persistent token caching was requested, but no persistence provider was configured.",
|
|
922
|
+
"You must install the identity-cache-persistence plugin package (`npm install --save @azure/identity-cache-persistence`)",
|
|
923
|
+
"and enable it by importing `useIdentityPlugin` from `@azure/identity` and calling",
|
|
924
|
+
"`useIdentityPlugin(cachePersistencePlugin)` before using `tokenCachePersistenceOptions`."
|
|
925
|
+
].join(" "));
|
|
895
926
|
}
|
|
896
927
|
this.azureRegion = (_c = options.regionalAuthority) !== null && _c !== void 0 ? _c : process.env.AZURE_REGIONAL_AUTHORITY_NAME;
|
|
897
|
-
if (this.azureRegion ===
|
|
928
|
+
if (this.azureRegion === RegionalAuthority.AutoDiscoverRegion) {
|
|
898
929
|
this.azureRegion = "AUTO_DISCOVER";
|
|
899
930
|
}
|
|
900
931
|
}
|
|
901
932
|
/**
|
|
902
|
-
* Generates a MSAL configuration that generally works for
|
|
933
|
+
* Generates a MSAL configuration that generally works for Node.js
|
|
903
934
|
*/
|
|
904
935
|
defaultNodeMsalConfig(options) {
|
|
905
936
|
const clientId = options.clientId || DeveloperSignOnClientId;
|
|
@@ -907,11 +938,16 @@ class MsalNode extends MsalBaseUtilities {
|
|
|
907
938
|
this.authorityHost = options.authorityHost || process.env.AZURE_AUTHORITY_HOST;
|
|
908
939
|
const authority = getAuthority(tenantId, this.authorityHost);
|
|
909
940
|
this.identityClient = new IdentityClient(Object.assign(Object.assign({}, options.tokenCredentialOptions), { authorityHost: authority }));
|
|
941
|
+
let clientCapabilities = ["CP1"];
|
|
942
|
+
if (process.env.AZURE_IDENTITY_DISABLE_CP1) {
|
|
943
|
+
clientCapabilities = [];
|
|
944
|
+
}
|
|
910
945
|
return {
|
|
911
946
|
auth: {
|
|
912
947
|
clientId,
|
|
913
948
|
authority,
|
|
914
|
-
knownAuthorities: getKnownAuthorities(tenantId, authority)
|
|
949
|
+
knownAuthorities: getKnownAuthorities(tenantId, authority),
|
|
950
|
+
clientCapabilities
|
|
915
951
|
},
|
|
916
952
|
// Cache is defined in this.prepare();
|
|
917
953
|
system: {
|
|
@@ -1005,7 +1041,11 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
|
|
|
1005
1041
|
var _a, _b;
|
|
1006
1042
|
await this.getActiveAccount();
|
|
1007
1043
|
if (!this.account) {
|
|
1008
|
-
throw new AuthenticationRequiredError(
|
|
1044
|
+
throw new AuthenticationRequiredError({
|
|
1045
|
+
scopes,
|
|
1046
|
+
getTokenOptions: options,
|
|
1047
|
+
message: "Silent authentication failed. We couldn't retrieve an active account from the cache."
|
|
1048
|
+
});
|
|
1009
1049
|
}
|
|
1010
1050
|
const silentRequest = {
|
|
1011
1051
|
// To be able to re-use the account, the Token Cache must also have been provided.
|
|
@@ -1028,21 +1068,27 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
|
|
|
1028
1068
|
* If disableAutomaticAuthentication is sent through the constructor, it will prevent MSAL from requesting the user input.
|
|
1029
1069
|
*/
|
|
1030
1070
|
async getToken(scopes, options = {}) {
|
|
1031
|
-
const tenantId = processMultiTenantRequest(this.tenantId,
|
|
1032
|
-
this.tenantId;
|
|
1071
|
+
const tenantId = processMultiTenantRequest(this.tenantId, options) || this.tenantId;
|
|
1033
1072
|
options.authority = getAuthority(tenantId, this.authorityHost);
|
|
1034
1073
|
options.correlationId = (options === null || options === void 0 ? void 0 : options.correlationId) || this.generateUuid();
|
|
1035
1074
|
await this.init(options);
|
|
1036
|
-
|
|
1075
|
+
try {
|
|
1076
|
+
return await this.getTokenSilent(scopes, options);
|
|
1077
|
+
}
|
|
1078
|
+
catch (err) {
|
|
1037
1079
|
if (err.name !== "AuthenticationRequiredError") {
|
|
1038
1080
|
throw err;
|
|
1039
1081
|
}
|
|
1040
1082
|
if (options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication) {
|
|
1041
|
-
throw new AuthenticationRequiredError(
|
|
1083
|
+
throw new AuthenticationRequiredError({
|
|
1084
|
+
scopes,
|
|
1085
|
+
getTokenOptions: options,
|
|
1086
|
+
message: "Automatic authentication has been disabled. You may call the authentication() method."
|
|
1087
|
+
});
|
|
1042
1088
|
}
|
|
1043
1089
|
this.logger.info(`Silent authentication failed, falling back to interactive method.`);
|
|
1044
1090
|
return this.doGetToken(scopes, options);
|
|
1045
|
-
}
|
|
1091
|
+
}
|
|
1046
1092
|
}
|
|
1047
1093
|
}
|
|
1048
1094
|
|
|
@@ -1107,7 +1153,7 @@ function getPropertyFromVSCode(property) {
|
|
|
1107
1153
|
}
|
|
1108
1154
|
}
|
|
1109
1155
|
/**
|
|
1110
|
-
*
|
|
1156
|
+
* Connects to Azure using the credential provided by the VSCode extension 'Azure Account'.
|
|
1111
1157
|
* Once the user has logged in via the extension, this credential can share the same refresh token
|
|
1112
1158
|
* that is cached by the extension.
|
|
1113
1159
|
*/
|
|
@@ -1115,6 +1161,11 @@ class VisualStudioCodeCredential {
|
|
|
1115
1161
|
/**
|
|
1116
1162
|
* Creates an instance of VisualStudioCodeCredential to use for automatically authenticating via VSCode.
|
|
1117
1163
|
*
|
|
1164
|
+
* **Note**: `VisualStudioCodeCredential` is provided by a plugin package:
|
|
1165
|
+
* `@azure/identity-vscode`. If this package is not installed and registered
|
|
1166
|
+
* using the plugin API (`useIdentityPlugin`), then authentication using
|
|
1167
|
+
* `VisualStudioCodeCredential` will not be available.
|
|
1168
|
+
*
|
|
1118
1169
|
* @param options - Options for configuring the client which makes the authentication request.
|
|
1119
1170
|
*/
|
|
1120
1171
|
constructor(options) {
|
|
@@ -1131,7 +1182,6 @@ class VisualStudioCodeCredential {
|
|
|
1131
1182
|
else {
|
|
1132
1183
|
this.tenantId = CommonTenantId;
|
|
1133
1184
|
}
|
|
1134
|
-
this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
|
|
1135
1185
|
checkUnsupportedTenant(this.tenantId);
|
|
1136
1186
|
}
|
|
1137
1187
|
/**
|
|
@@ -1165,10 +1215,14 @@ class VisualStudioCodeCredential {
|
|
|
1165
1215
|
async getToken(scopes, options) {
|
|
1166
1216
|
var _a, _b;
|
|
1167
1217
|
await this.prepareOnce();
|
|
1168
|
-
const tenantId = processMultiTenantRequest(this.tenantId,
|
|
1169
|
-
this.tenantId;
|
|
1218
|
+
const tenantId = processMultiTenantRequest(this.tenantId, options) || this.tenantId;
|
|
1170
1219
|
if (findCredentials === undefined) {
|
|
1171
|
-
throw new CredentialUnavailableError(
|
|
1220
|
+
throw new CredentialUnavailableError([
|
|
1221
|
+
"No implementation of `VisualStudioCodeCredential` is available.",
|
|
1222
|
+
"You must install the identity-vscode plugin package (`npm install --save-dev @azure/identity-vscode`)",
|
|
1223
|
+
"and enable it by importing `useIdentityPlugin` from `@azure/identity` and calling",
|
|
1224
|
+
"`useIdentityPlugin(vsCodePlugin)` before creating a `VisualStudioCodeCredential`."
|
|
1225
|
+
].join(" "));
|
|
1172
1226
|
}
|
|
1173
1227
|
let scopeString = typeof scopes === "string" ? scopes : scopes.join(" ");
|
|
1174
1228
|
// Check to make sure the scope we get back is a valid scope
|
|
@@ -1198,13 +1252,13 @@ class VisualStudioCodeCredential {
|
|
|
1198
1252
|
return tokenResponse.accessToken;
|
|
1199
1253
|
}
|
|
1200
1254
|
else {
|
|
1201
|
-
const error = new CredentialUnavailableError("Could not retrieve the token associated with Visual Studio Code. Have you connected using the 'Azure Account' extension recently?");
|
|
1255
|
+
const error = new CredentialUnavailableError("Could not retrieve the token associated with Visual Studio Code. Have you connected using the 'Azure Account' extension recently? To troubleshoot, visit https://aka.ms/azsdk/js/identity/visualstudiocodecredential/troubleshoot.");
|
|
1202
1256
|
logger$1.getToken.info(formatError(scopes, error));
|
|
1203
1257
|
throw error;
|
|
1204
1258
|
}
|
|
1205
1259
|
}
|
|
1206
1260
|
else {
|
|
1207
|
-
const error = new CredentialUnavailableError("Could not retrieve the token associated with Visual Studio Code. Did you connect using the 'Azure Account' extension?");
|
|
1261
|
+
const error = new CredentialUnavailableError("Could not retrieve the token associated with Visual Studio Code. Did you connect using the 'Azure Account' extension? To troubleshoot, visit https://aka.ms/azsdk/js/identity/visualstudiocodecredential/troubleshoot.");
|
|
1208
1262
|
logger$1.getToken.info(formatError(scopes, error));
|
|
1209
1263
|
throw error;
|
|
1210
1264
|
}
|
|
@@ -1213,17 +1267,17 @@ class VisualStudioCodeCredential {
|
|
|
1213
1267
|
|
|
1214
1268
|
// Copyright (c) Microsoft Corporation.
|
|
1215
1269
|
/**
|
|
1216
|
-
* The context passed to an Identity
|
|
1217
|
-
*
|
|
1270
|
+
* The context passed to an Identity plugin. This contains objects that
|
|
1271
|
+
* plugins can use to set backend implementations.
|
|
1218
1272
|
* @internal
|
|
1219
1273
|
*/
|
|
1220
|
-
const
|
|
1274
|
+
const pluginContext = {
|
|
1221
1275
|
cachePluginControl: msalNodeFlowCacheControl,
|
|
1222
1276
|
vsCodeCredentialControl: vsCodeCredentialControl
|
|
1223
1277
|
};
|
|
1224
1278
|
/**
|
|
1225
|
-
* Extend Azure Identity with additional functionality. Pass
|
|
1226
|
-
*
|
|
1279
|
+
* Extend Azure Identity with additional functionality. Pass a plugin from
|
|
1280
|
+
* a plugin package, such as:
|
|
1227
1281
|
*
|
|
1228
1282
|
* - `@azure/identity-cache-persistence`: provides persistent token caching
|
|
1229
1283
|
* - `@azure/identity-vscode`: provides the dependencies of
|
|
@@ -1232,12 +1286,12 @@ const extensionContext = {
|
|
|
1232
1286
|
* Example:
|
|
1233
1287
|
*
|
|
1234
1288
|
* ```javascript
|
|
1235
|
-
* import {
|
|
1289
|
+
* import { cachePersistencePlugin } from "@azure/identity-cache-persistence";
|
|
1236
1290
|
*
|
|
1237
|
-
* import {
|
|
1238
|
-
*
|
|
1291
|
+
* import { useIdentityPlugin, DefaultAzureCredential } from "@azure/identity";
|
|
1292
|
+
* useIdentityPlugin(cachePersistencePlugin);
|
|
1239
1293
|
*
|
|
1240
|
-
* // The
|
|
1294
|
+
* // The plugin has the capability to extend `DefaultAzureCredential` and to
|
|
1241
1295
|
* // add middleware to the underlying credentials, such as persistence.
|
|
1242
1296
|
* const credential = new DefaultAzureCredential({
|
|
1243
1297
|
* tokenCachePersistenceOptions: {
|
|
@@ -1246,10 +1300,10 @@ const extensionContext = {
|
|
|
1246
1300
|
* });
|
|
1247
1301
|
* ```
|
|
1248
1302
|
*
|
|
1249
|
-
* @param
|
|
1303
|
+
* @param plugin - the plugin to register
|
|
1250
1304
|
*/
|
|
1251
|
-
function
|
|
1252
|
-
|
|
1305
|
+
function useIdentityPlugin(plugin) {
|
|
1306
|
+
plugin(pluginContext);
|
|
1253
1307
|
}
|
|
1254
1308
|
|
|
1255
1309
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -1299,7 +1353,7 @@ class ChainedTokenCredential {
|
|
|
1299
1353
|
let token = null;
|
|
1300
1354
|
let successfulCredentialName = "";
|
|
1301
1355
|
const errors = [];
|
|
1302
|
-
const { span, updatedOptions } = createSpan("ChainedTokenCredential
|
|
1356
|
+
const { span, updatedOptions } = createSpan("ChainedTokenCredential.getToken", options);
|
|
1303
1357
|
for (let i = 0; i < this._sources.length && token === null; i++) {
|
|
1304
1358
|
try {
|
|
1305
1359
|
token = await this._sources[i].getToken(scopes, updatedOptions);
|
|
@@ -1317,7 +1371,7 @@ class ChainedTokenCredential {
|
|
|
1317
1371
|
}
|
|
1318
1372
|
}
|
|
1319
1373
|
if (!token && errors.length > 0) {
|
|
1320
|
-
const err = new AggregateAuthenticationError(errors);
|
|
1374
|
+
const err = new AggregateAuthenticationError(errors, "ChainedTokenCredential authentication failed.");
|
|
1321
1375
|
span.setStatus({
|
|
1322
1376
|
code: coreTracing.SpanStatusCode.ERROR,
|
|
1323
1377
|
message: err.message
|
|
@@ -1386,15 +1440,15 @@ const cliCredentialInternals = {
|
|
|
1386
1440
|
}
|
|
1387
1441
|
return new Promise((resolve, reject) => {
|
|
1388
1442
|
try {
|
|
1389
|
-
|
|
1443
|
+
child_process__default.execFile("az", [
|
|
1390
1444
|
"account",
|
|
1391
1445
|
"get-access-token",
|
|
1392
1446
|
"--output",
|
|
1393
1447
|
"json",
|
|
1394
1448
|
"--resource",
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
], { cwd: cliCredentialInternals.getSafeWorkingDir() }, (error, stdout, stderr) => {
|
|
1449
|
+
resource,
|
|
1450
|
+
...tenantSection
|
|
1451
|
+
], { cwd: cliCredentialInternals.getSafeWorkingDir(), shell: true }, (error, stdout, stderr) => {
|
|
1398
1452
|
resolve({ stdout: stdout, stderr: stderr, error });
|
|
1399
1453
|
});
|
|
1400
1454
|
}
|
|
@@ -1410,18 +1464,18 @@ const logger$3 = credentialLogger("AzureCliCredential");
|
|
|
1410
1464
|
* via the Azure CLI ('az') commandline tool.
|
|
1411
1465
|
* To do so, it will read the user access token and expire time
|
|
1412
1466
|
* with Azure CLI command "az account get-access-token".
|
|
1413
|
-
* To be able to use this credential, ensure that you have already logged
|
|
1414
|
-
* in via the 'az' tool using the command "az login" from the commandline.
|
|
1415
1467
|
*/
|
|
1416
1468
|
class AzureCliCredential {
|
|
1417
1469
|
/**
|
|
1418
1470
|
* Creates an instance of the {@link AzureCliCredential}.
|
|
1419
1471
|
*
|
|
1472
|
+
* To use this credential, ensure that you have already logged
|
|
1473
|
+
* in via the 'az' tool using the command "az login" from the commandline.
|
|
1474
|
+
*
|
|
1420
1475
|
* @param options - Options, to optionally allow multi-tenant requests.
|
|
1421
1476
|
*/
|
|
1422
1477
|
constructor(options) {
|
|
1423
1478
|
this.tenantId = options === null || options === void 0 ? void 0 : options.tenantId;
|
|
1424
|
-
this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
|
|
1425
1479
|
}
|
|
1426
1480
|
/**
|
|
1427
1481
|
* Authenticates with Azure Active Directory and returns an access token if successful.
|
|
@@ -1432,7 +1486,7 @@ class AzureCliCredential {
|
|
|
1432
1486
|
* TokenCredential implementation might make.
|
|
1433
1487
|
*/
|
|
1434
1488
|
async getToken(scopes, options) {
|
|
1435
|
-
const tenantId = processMultiTenantRequest(this.tenantId,
|
|
1489
|
+
const tenantId = processMultiTenantRequest(this.tenantId, options);
|
|
1436
1490
|
if (tenantId) {
|
|
1437
1491
|
checkTenantId(logger$3, tenantId);
|
|
1438
1492
|
}
|
|
@@ -1441,7 +1495,7 @@ class AzureCliCredential {
|
|
|
1441
1495
|
ensureValidScope(scope, logger$3);
|
|
1442
1496
|
const resource = getScopeResource(scope);
|
|
1443
1497
|
let responseData = "";
|
|
1444
|
-
const { span } = createSpan("AzureCliCredential
|
|
1498
|
+
const { span } = createSpan("AzureCliCredential.getToken", options);
|
|
1445
1499
|
try {
|
|
1446
1500
|
const obj = await cliCredentialInternals.getAzureCliAccessToken(resource, tenantId);
|
|
1447
1501
|
if (obj.stderr) {
|
|
@@ -1558,7 +1612,8 @@ const powerShellErrors = {
|
|
|
1558
1612
|
*/
|
|
1559
1613
|
const powerShellPublicErrorMessages = {
|
|
1560
1614
|
login: "Please run 'Connect-AzAccount' from PowerShell to authenticate before using this credential.",
|
|
1561
|
-
installed: `The 'Az.Account' module >= 2.2.0 is not installed. Install the Azure Az PowerShell module with: "Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force"
|
|
1615
|
+
installed: `The 'Az.Account' module >= 2.2.0 is not installed. Install the Azure Az PowerShell module with: "Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force".`,
|
|
1616
|
+
troubleshoot: `To troubleshoot, visit https://aka.ms/azsdk/js/identity/powershellcredential/troubleshoot.`
|
|
1562
1617
|
};
|
|
1563
1618
|
// PowerShell Azure User not logged in error check.
|
|
1564
1619
|
const isLoginError = (err) => err.message.match(`(.*)${powerShellErrors.login}(.*)`);
|
|
@@ -1577,22 +1632,21 @@ if (isWindows) {
|
|
|
1577
1632
|
* This credential will use the currently logged-in user information from the
|
|
1578
1633
|
* Azure PowerShell module. To do so, it will read the user access token and
|
|
1579
1634
|
* expire time with Azure PowerShell command `Get-AzAccessToken -ResourceUrl {ResourceScope}`
|
|
1580
|
-
*
|
|
1581
|
-
* To be able to use this credential:
|
|
1582
|
-
* - Install the Azure Az PowerShell module with:
|
|
1583
|
-
* `Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force`.
|
|
1584
|
-
* - You have already logged in to Azure PowerShell using the command
|
|
1585
|
-
* `Connect-AzAccount` from the command line.
|
|
1586
1635
|
*/
|
|
1587
1636
|
class AzurePowerShellCredential {
|
|
1588
1637
|
/**
|
|
1589
|
-
* Creates an instance of the {@link
|
|
1638
|
+
* Creates an instance of the {@link AzurePowerShellCredential}.
|
|
1639
|
+
*
|
|
1640
|
+
* To use this credential:
|
|
1641
|
+
* - Install the Azure Az PowerShell module with:
|
|
1642
|
+
* `Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force`.
|
|
1643
|
+
* - You have already logged in to Azure PowerShell using the command
|
|
1644
|
+
* `Connect-AzAccount` from the command line.
|
|
1590
1645
|
*
|
|
1591
1646
|
* @param options - Options, to optionally allow multi-tenant requests.
|
|
1592
1647
|
*/
|
|
1593
1648
|
constructor(options) {
|
|
1594
1649
|
this.tenantId = options === null || options === void 0 ? void 0 : options.tenantId;
|
|
1595
|
-
this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
|
|
1596
1650
|
}
|
|
1597
1651
|
/**
|
|
1598
1652
|
* Gets the access token from Azure PowerShell
|
|
@@ -1633,7 +1687,7 @@ class AzurePowerShellCredential {
|
|
|
1633
1687
|
throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);
|
|
1634
1688
|
}
|
|
1635
1689
|
}
|
|
1636
|
-
throw new Error(`Unable to execute PowerShell. Ensure that it is installed in your system
|
|
1690
|
+
throw new Error(`Unable to execute PowerShell. Ensure that it is installed in your system`);
|
|
1637
1691
|
}
|
|
1638
1692
|
/**
|
|
1639
1693
|
* Authenticates with Azure Active Directory and returns an access token if successful.
|
|
@@ -1644,7 +1698,7 @@ class AzurePowerShellCredential {
|
|
|
1644
1698
|
*/
|
|
1645
1699
|
async getToken(scopes, options = {}) {
|
|
1646
1700
|
return trace(`${this.constructor.name}.getToken`, options, async () => {
|
|
1647
|
-
const tenantId = processMultiTenantRequest(this.tenantId,
|
|
1701
|
+
const tenantId = processMultiTenantRequest(this.tenantId, options);
|
|
1648
1702
|
if (tenantId) {
|
|
1649
1703
|
checkTenantId(logger$4, tenantId);
|
|
1650
1704
|
}
|
|
@@ -1671,7 +1725,7 @@ class AzurePowerShellCredential {
|
|
|
1671
1725
|
logger$4.getToken.info(formatError(scope, error));
|
|
1672
1726
|
throw error;
|
|
1673
1727
|
}
|
|
1674
|
-
const error = new CredentialUnavailableError(err);
|
|
1728
|
+
const error = new CredentialUnavailableError(`${err}. ${powerShellPublicErrorMessages.troubleshoot}`);
|
|
1675
1729
|
logger$4.getToken.info(formatError(scope, error));
|
|
1676
1730
|
throw error;
|
|
1677
1731
|
}
|
|
@@ -1730,6 +1784,9 @@ class ClientSecretCredential {
|
|
|
1730
1784
|
* @param options - Options for configuring the client which makes the authentication request.
|
|
1731
1785
|
*/
|
|
1732
1786
|
constructor(tenantId, clientId, clientSecret, options = {}) {
|
|
1787
|
+
if (!tenantId || !clientId || !clientSecret) {
|
|
1788
|
+
throw new Error("ClientSecretCredential: tenantId, clientId, and clientSecret are required parameters. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.");
|
|
1789
|
+
}
|
|
1733
1790
|
this.msalFlow = new MsalClientSecret(Object.assign(Object.assign({}, options), { logger: logger$5,
|
|
1734
1791
|
clientId,
|
|
1735
1792
|
tenantId,
|
|
@@ -1752,6 +1809,41 @@ class ClientSecretCredential {
|
|
|
1752
1809
|
}
|
|
1753
1810
|
|
|
1754
1811
|
// Copyright (c) Microsoft Corporation.
|
|
1812
|
+
const readFileAsync = util.promisify(fs.readFile);
|
|
1813
|
+
/**
|
|
1814
|
+
* Tries to asynchronously load a certificate from the given path.
|
|
1815
|
+
*
|
|
1816
|
+
* @param configuration - Either the PEM value or the path to the certificate.
|
|
1817
|
+
* @param sendCertificateChain - Option to include x5c header for SubjectName and Issuer name authorization.
|
|
1818
|
+
* @returns - The certificate parts, or `undefined` if the certificate could not be loaded.
|
|
1819
|
+
* @internal
|
|
1820
|
+
*/
|
|
1821
|
+
async function parseCertificate(configuration, sendCertificateChain) {
|
|
1822
|
+
const certificateParts = {};
|
|
1823
|
+
certificateParts.certificateContents =
|
|
1824
|
+
configuration.certificate || (await readFileAsync(configuration.certificatePath, "utf8"));
|
|
1825
|
+
if (sendCertificateChain) {
|
|
1826
|
+
certificateParts.x5c = certificateParts.certificateContents;
|
|
1827
|
+
}
|
|
1828
|
+
const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
|
|
1829
|
+
const publicKeys = [];
|
|
1830
|
+
// Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
|
|
1831
|
+
let match;
|
|
1832
|
+
do {
|
|
1833
|
+
match = certificatePattern.exec(certificateParts.certificateContents);
|
|
1834
|
+
if (match) {
|
|
1835
|
+
publicKeys.push(match[3]);
|
|
1836
|
+
}
|
|
1837
|
+
} while (match);
|
|
1838
|
+
if (publicKeys.length === 0) {
|
|
1839
|
+
throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
|
|
1840
|
+
}
|
|
1841
|
+
certificateParts.thumbprint = crypto.createHash("sha1")
|
|
1842
|
+
.update(Buffer.from(publicKeys[0], "base64"))
|
|
1843
|
+
.digest("hex")
|
|
1844
|
+
.toUpperCase();
|
|
1845
|
+
return certificateParts;
|
|
1846
|
+
}
|
|
1755
1847
|
/**
|
|
1756
1848
|
* MSAL client certificate client. Calls to MSAL's confidential application's `acquireTokenByClientCredential` during `doGetToken`.
|
|
1757
1849
|
* @internal
|
|
@@ -1760,40 +1852,24 @@ class MsalClientCertificate extends MsalNode {
|
|
|
1760
1852
|
constructor(options) {
|
|
1761
1853
|
super(options);
|
|
1762
1854
|
this.requiresConfidential = true;
|
|
1855
|
+
this.configuration = options.configuration;
|
|
1763
1856
|
this.sendCertificateChain = options.sendCertificateChain;
|
|
1764
|
-
const parts = this.parseCertificate(options.certificatePath);
|
|
1765
|
-
this.msalConfig.auth.clientCertificate = {
|
|
1766
|
-
thumbprint: parts.thumbprint,
|
|
1767
|
-
privateKey: parts.certificateContents,
|
|
1768
|
-
x5c: parts.x5c
|
|
1769
|
-
};
|
|
1770
1857
|
}
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
match = certificatePattern.exec(certificateParts.certificateContents);
|
|
1783
|
-
if (match) {
|
|
1784
|
-
publicKeys.push(match[3]);
|
|
1785
|
-
}
|
|
1786
|
-
} while (match);
|
|
1787
|
-
if (publicKeys.length === 0) {
|
|
1788
|
-
const error = new Error("The file at the specified path does not contain a PEM-encoded certificate.");
|
|
1858
|
+
// Changing the MSAL configuration asynchronously
|
|
1859
|
+
async init(options) {
|
|
1860
|
+
try {
|
|
1861
|
+
const parts = await parseCertificate(this.configuration, this.sendCertificateChain);
|
|
1862
|
+
this.msalConfig.auth.clientCertificate = {
|
|
1863
|
+
thumbprint: parts.thumbprint,
|
|
1864
|
+
privateKey: parts.certificateContents,
|
|
1865
|
+
x5c: parts.x5c
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
catch (error) {
|
|
1789
1869
|
this.logger.info(formatError("", error));
|
|
1790
1870
|
throw error;
|
|
1791
1871
|
}
|
|
1792
|
-
|
|
1793
|
-
.update(Buffer.from(publicKeys[0], "base64"))
|
|
1794
|
-
.digest("hex")
|
|
1795
|
-
.toUpperCase();
|
|
1796
|
-
return certificateParts;
|
|
1872
|
+
return super.init(options);
|
|
1797
1873
|
}
|
|
1798
1874
|
async doGetToken(scopes, options = {}) {
|
|
1799
1875
|
try {
|
|
@@ -1815,7 +1891,8 @@ class MsalClientCertificate extends MsalNode {
|
|
|
1815
1891
|
}
|
|
1816
1892
|
|
|
1817
1893
|
// Copyright (c) Microsoft Corporation.
|
|
1818
|
-
const
|
|
1894
|
+
const credentialName = "ClientCertificateCredential";
|
|
1895
|
+
const logger$6 = credentialLogger(credentialName);
|
|
1819
1896
|
/**
|
|
1820
1897
|
* Enables authentication to Azure Active Directory using a PEM-encoded
|
|
1821
1898
|
* certificate that is assigned to an App Registration. More information
|
|
@@ -1825,17 +1902,22 @@ const logger$6 = credentialLogger("ClientCertificateCredential");
|
|
|
1825
1902
|
*
|
|
1826
1903
|
*/
|
|
1827
1904
|
class ClientCertificateCredential {
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1905
|
+
constructor(tenantId, clientId, certificatePathOrConfiguration, options = {}) {
|
|
1906
|
+
if (!tenantId || !clientId) {
|
|
1907
|
+
throw new Error(`${credentialName}: tenantId and clientId are required parameters.`);
|
|
1908
|
+
}
|
|
1909
|
+
const configuration = Object.assign({}, (typeof certificatePathOrConfiguration === "string"
|
|
1910
|
+
? {
|
|
1911
|
+
certificatePath: certificatePathOrConfiguration
|
|
1912
|
+
}
|
|
1913
|
+
: certificatePathOrConfiguration));
|
|
1914
|
+
if (!configuration || !(configuration.certificate || configuration.certificatePath)) {
|
|
1915
|
+
throw new Error(`${credentialName}: Provide either a PEM certificate in string form, or the path to that certificate in the filesystem. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
|
|
1916
|
+
}
|
|
1917
|
+
if (configuration.certificate && configuration.certificatePath) {
|
|
1918
|
+
throw new Error(`${credentialName}: To avoid unexpected behaviors, providing both the contents of a PEM certificate and the path to a PEM certificate is forbidden. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
|
|
1919
|
+
}
|
|
1920
|
+
this.msalFlow = new MsalClientCertificate(Object.assign(Object.assign({}, options), { configuration,
|
|
1839
1921
|
logger: logger$6,
|
|
1840
1922
|
clientId,
|
|
1841
1923
|
tenantId, sendCertificateChain: options.sendCertificateChain, tokenCredentialOptions: options }));
|
|
@@ -1849,7 +1931,7 @@ class ClientCertificateCredential {
|
|
|
1849
1931
|
* TokenCredential implementation might make.
|
|
1850
1932
|
*/
|
|
1851
1933
|
async getToken(scopes, options = {}) {
|
|
1852
|
-
return trace(`${
|
|
1934
|
+
return trace(`${credentialName}.getToken`, options, async (newOptions) => {
|
|
1853
1935
|
const arrayScopes = Array.isArray(scopes) ? scopes : [scopes];
|
|
1854
1936
|
return this.msalFlow.getToken(arrayScopes, newOptions);
|
|
1855
1937
|
});
|
|
@@ -1893,8 +1975,6 @@ const logger$7 = credentialLogger("UsernamePasswordCredential");
|
|
|
1893
1975
|
* trust so you should only use it when other, more secure credential
|
|
1894
1976
|
* types can't be used.
|
|
1895
1977
|
*/
|
|
1896
|
-
// We'll be using InteractiveCredential as the base of this class, which requires us to support authenticate(),
|
|
1897
|
-
// to reduce the number of times we send the password over the network.
|
|
1898
1978
|
class UsernamePasswordCredential {
|
|
1899
1979
|
/**
|
|
1900
1980
|
* Creates an instance of the UsernamePasswordCredential with the details
|
|
@@ -1908,6 +1988,9 @@ class UsernamePasswordCredential {
|
|
|
1908
1988
|
* @param options - Options for configuring the client which makes the authentication request.
|
|
1909
1989
|
*/
|
|
1910
1990
|
constructor(tenantId, clientId, username, password, options = {}) {
|
|
1991
|
+
if (!tenantId || !clientId || !username || !password) {
|
|
1992
|
+
throw new Error("UsernamePasswordCredential: tenantId, clientId, username and password are required parameters. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
|
|
1993
|
+
}
|
|
1911
1994
|
this.msalFlow = new MsalUsernamePassword(Object.assign(Object.assign({}, options), { logger: logger$7,
|
|
1912
1995
|
clientId,
|
|
1913
1996
|
tenantId,
|
|
@@ -1953,23 +2036,7 @@ const AllSupportedEnvironmentVariables = [
|
|
|
1953
2036
|
const logger$8 = credentialLogger("EnvironmentCredential");
|
|
1954
2037
|
/**
|
|
1955
2038
|
* Enables authentication to Azure Active Directory using client secret
|
|
1956
|
-
* details configured in
|
|
1957
|
-
*
|
|
1958
|
-
* Required environment variables:
|
|
1959
|
-
* - `AZURE_TENANT_ID`: The Azure Active Directory tenant (directory) ID.
|
|
1960
|
-
* - `AZURE_CLIENT_ID`: The client (application) ID of an App Registration in the tenant.
|
|
1961
|
-
*
|
|
1962
|
-
* Environment variables used for client credential authentication:
|
|
1963
|
-
* - `AZURE_CLIENT_SECRET`: A client secret that was generated for the App Registration.
|
|
1964
|
-
* - `AZURE_CLIENT_CERTIFICATE_PATH`: The path to a PEM certificate to use during the authentication, instead of the client secret.
|
|
1965
|
-
*
|
|
1966
|
-
* Alternatively, users can provide environment variables for username and password authentication:
|
|
1967
|
-
* - `AZURE_USERNAME`: Username to authenticate with.
|
|
1968
|
-
* - `AZURE_PASSWORD`: Password to authenticate with.
|
|
1969
|
-
*
|
|
1970
|
-
* This credential ultimately uses a {@link ClientSecretCredential} to
|
|
1971
|
-
* perform the authentication using these details. Please consult the
|
|
1972
|
-
* documentation of that class for more details.
|
|
2039
|
+
* details configured in environment variables
|
|
1973
2040
|
*/
|
|
1974
2041
|
class EnvironmentCredential {
|
|
1975
2042
|
/**
|
|
@@ -2009,7 +2076,7 @@ class EnvironmentCredential {
|
|
|
2009
2076
|
const certificatePath = process.env.AZURE_CLIENT_CERTIFICATE_PATH;
|
|
2010
2077
|
if (tenantId && clientId && certificatePath) {
|
|
2011
2078
|
logger$8.info(`Invoking ClientCertificateCredential with tenant ID: ${tenantId}, clientId: ${clientId} and certificatePath: ${certificatePath}`);
|
|
2012
|
-
this._credential = new ClientCertificateCredential(tenantId, clientId, certificatePath, options);
|
|
2079
|
+
this._credential = new ClientCertificateCredential(tenantId, clientId, { certificatePath }, options);
|
|
2013
2080
|
return;
|
|
2014
2081
|
}
|
|
2015
2082
|
const username = process.env.AZURE_USERNAME;
|
|
@@ -2035,7 +2102,7 @@ class EnvironmentCredential {
|
|
|
2035
2102
|
}
|
|
2036
2103
|
catch (err) {
|
|
2037
2104
|
const authenticationError = new AuthenticationError(400, {
|
|
2038
|
-
error: "EnvironmentCredential authentication failed.",
|
|
2105
|
+
error: "EnvironmentCredential authentication failed. To troubleshoot, visit https://aka.ms/azsdk/js/identity/environmentcredential/troubleshoot.",
|
|
2039
2106
|
error_description: err.message
|
|
2040
2107
|
.toString()
|
|
2041
2108
|
.split("More details:")
|
|
@@ -2045,7 +2112,7 @@ class EnvironmentCredential {
|
|
|
2045
2112
|
throw authenticationError;
|
|
2046
2113
|
}
|
|
2047
2114
|
}
|
|
2048
|
-
throw new CredentialUnavailableError("EnvironmentCredential is unavailable. No underlying credential could be used.");
|
|
2115
|
+
throw new CredentialUnavailableError("EnvironmentCredential is unavailable. No underlying credential could be used. To troubleshoot, visit https://aka.ms/azsdk/js/identity/environmentcredential/troubleshoot.");
|
|
2049
2116
|
});
|
|
2050
2117
|
}
|
|
2051
2118
|
}
|
|
@@ -2053,16 +2120,26 @@ class EnvironmentCredential {
|
|
|
2053
2120
|
// Copyright (c) Microsoft Corporation.
|
|
2054
2121
|
// Licensed under the MIT license.
|
|
2055
2122
|
const DefaultScopeSuffix = "/.default";
|
|
2056
|
-
const
|
|
2123
|
+
const imdsHost = "http://169.254.169.254";
|
|
2124
|
+
const imdsEndpointPath = "/metadata/identity/oauth2/token";
|
|
2057
2125
|
const imdsApiVersion = "2018-02-01";
|
|
2058
2126
|
const azureArcAPIVersion = "2019-11-01";
|
|
2127
|
+
const azureFabricVersion = "2019-07-01-preview";
|
|
2059
2128
|
|
|
2060
2129
|
// Copyright (c) Microsoft Corporation.
|
|
2130
|
+
/**
|
|
2131
|
+
* Most MSIs send requests to the IMDS endpoint, or a similar endpoint. These are GET requests that require sending a `resource` parameter on the query.
|
|
2132
|
+
* This resource can be derived from the scopes received through the getToken call, as long as only one scope is received.
|
|
2133
|
+
* Multiple scopes assume that the resulting token will have access to multiple resources, which won't be the case.
|
|
2134
|
+
*
|
|
2135
|
+
* For that reason, when we encounter multiple scopes, we return undefined.
|
|
2136
|
+
* It's up to the individual MSI implementations to throw the errors (which helps us provide less generic errors).
|
|
2137
|
+
*/
|
|
2061
2138
|
function mapScopesToResource(scopes) {
|
|
2062
2139
|
let scope = "";
|
|
2063
2140
|
if (Array.isArray(scopes)) {
|
|
2064
2141
|
if (scopes.length !== 1) {
|
|
2065
|
-
|
|
2142
|
+
return;
|
|
2066
2143
|
}
|
|
2067
2144
|
scope = scopes[0];
|
|
2068
2145
|
}
|
|
@@ -2074,81 +2151,177 @@ function mapScopesToResource(scopes) {
|
|
|
2074
2151
|
}
|
|
2075
2152
|
return scope.substr(0, scope.lastIndexOf(DefaultScopeSuffix));
|
|
2076
2153
|
}
|
|
2077
|
-
async function msiGenericGetToken(identityClient, requestOptions, expiresInParser, getTokenOptions = {}) {
|
|
2078
|
-
const
|
|
2079
|
-
|
|
2154
|
+
async function msiGenericGetToken(identityClient, requestOptions, expiresInParser, getTokenOptions = {}, agent) {
|
|
2155
|
+
const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, requestOptions), { allowInsecureConnection: true }));
|
|
2156
|
+
if (agent) {
|
|
2157
|
+
request.agent = agent;
|
|
2158
|
+
}
|
|
2159
|
+
const tokenResponse = await identityClient.sendTokenRequest(request, expiresInParser);
|
|
2080
2160
|
return (tokenResponse && tokenResponse.accessToken) || null;
|
|
2081
2161
|
}
|
|
2082
2162
|
|
|
2083
2163
|
// Copyright (c) Microsoft Corporation.
|
|
2084
|
-
const
|
|
2164
|
+
const msiName = "ManagedIdentityCredential - AppServiceMSI 2017";
|
|
2165
|
+
const logger$9 = credentialLogger(msiName);
|
|
2166
|
+
function expiresInParser(requestBody) {
|
|
2167
|
+
// Parse a date format like "06/20/2019 02:57:58 +00:00" and
|
|
2168
|
+
// convert it into a JavaScript-formatted date
|
|
2169
|
+
return Date.parse(requestBody.expires_on);
|
|
2170
|
+
}
|
|
2171
|
+
function prepareRequestOptions(scopes, clientId) {
|
|
2172
|
+
const resource = mapScopesToResource(scopes);
|
|
2173
|
+
if (!resource) {
|
|
2174
|
+
throw new Error(`${msiName}: Multiple scopes are not supported.`);
|
|
2175
|
+
}
|
|
2176
|
+
const queryParameters = {
|
|
2177
|
+
resource,
|
|
2178
|
+
"api-version": "2017-09-01"
|
|
2179
|
+
};
|
|
2180
|
+
if (clientId) {
|
|
2181
|
+
queryParameters.clientid = clientId;
|
|
2182
|
+
}
|
|
2183
|
+
const query = new URLSearchParams(queryParameters);
|
|
2184
|
+
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
2185
|
+
if (!process.env.MSI_ENDPOINT) {
|
|
2186
|
+
throw new Error(`${msiName}: Missing environment variable: MSI_ENDPOINT`);
|
|
2187
|
+
}
|
|
2188
|
+
if (!process.env.MSI_SECRET) {
|
|
2189
|
+
throw new Error(`${msiName}: Missing environment variable: MSI_SECRET`);
|
|
2190
|
+
}
|
|
2191
|
+
return {
|
|
2192
|
+
url: `${process.env.MSI_ENDPOINT}?${query.toString()}`,
|
|
2193
|
+
method: "GET",
|
|
2194
|
+
headers: coreRestPipeline.createHttpHeaders({
|
|
2195
|
+
Accept: "application/json",
|
|
2196
|
+
secret: process.env.MSI_SECRET
|
|
2197
|
+
})
|
|
2198
|
+
};
|
|
2199
|
+
}
|
|
2200
|
+
const appServiceMsi2017 = {
|
|
2201
|
+
async isAvailable(scopes) {
|
|
2202
|
+
const resource = mapScopesToResource(scopes);
|
|
2203
|
+
if (!resource) {
|
|
2204
|
+
logger$9.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
|
|
2205
|
+
return false;
|
|
2206
|
+
}
|
|
2207
|
+
const env = process.env;
|
|
2208
|
+
const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);
|
|
2209
|
+
if (!result) {
|
|
2210
|
+
logger$9.info(`${msiName}: Unavailable. The environment variables needed are: MSI_ENDPOINT and MSI_SECRET.`);
|
|
2211
|
+
}
|
|
2212
|
+
return result;
|
|
2213
|
+
},
|
|
2214
|
+
async getToken(configuration, getTokenOptions = {}) {
|
|
2215
|
+
const { identityClient, scopes, clientId } = configuration;
|
|
2216
|
+
logger$9.info(`${msiName}: Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`);
|
|
2217
|
+
return msiGenericGetToken(identityClient, prepareRequestOptions(scopes, clientId), expiresInParser, getTokenOptions);
|
|
2218
|
+
}
|
|
2219
|
+
};
|
|
2220
|
+
|
|
2221
|
+
// Copyright (c) Microsoft Corporation.
|
|
2222
|
+
const msiName$1 = "ManagedIdentityCredential - CloudShellMSI";
|
|
2223
|
+
const logger$a = credentialLogger(msiName$1);
|
|
2085
2224
|
// Cloud Shell MSI doesn't have a special expiresIn parser.
|
|
2086
|
-
const expiresInParser = undefined;
|
|
2087
|
-
function prepareRequestOptions(
|
|
2225
|
+
const expiresInParser$1 = undefined;
|
|
2226
|
+
function prepareRequestOptions$1(scopes, clientId) {
|
|
2227
|
+
const resource = mapScopesToResource(scopes);
|
|
2228
|
+
if (!resource) {
|
|
2229
|
+
throw new Error(`${msiName$1}: Multiple scopes are not supported.`);
|
|
2230
|
+
}
|
|
2088
2231
|
const body = {
|
|
2089
2232
|
resource
|
|
2090
2233
|
};
|
|
2091
2234
|
if (clientId) {
|
|
2092
2235
|
body.client_id = clientId;
|
|
2093
2236
|
}
|
|
2237
|
+
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
2238
|
+
if (!process.env.MSI_ENDPOINT) {
|
|
2239
|
+
throw new Error(`${msiName$1}: Missing environment variable: MSI_ENDPOINT`);
|
|
2240
|
+
}
|
|
2241
|
+
const params = new URLSearchParams(body);
|
|
2094
2242
|
return {
|
|
2095
2243
|
url: process.env.MSI_ENDPOINT,
|
|
2096
2244
|
method: "POST",
|
|
2097
|
-
body:
|
|
2098
|
-
headers: {
|
|
2245
|
+
body: params.toString(),
|
|
2246
|
+
headers: coreRestPipeline.createHttpHeaders({
|
|
2099
2247
|
Accept: "application/json",
|
|
2100
|
-
Metadata: true,
|
|
2248
|
+
Metadata: "true",
|
|
2101
2249
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
2102
|
-
}
|
|
2250
|
+
})
|
|
2103
2251
|
};
|
|
2104
2252
|
}
|
|
2105
2253
|
const cloudShellMsi = {
|
|
2106
|
-
async isAvailable() {
|
|
2254
|
+
async isAvailable(scopes) {
|
|
2255
|
+
const resource = mapScopesToResource(scopes);
|
|
2256
|
+
if (!resource) {
|
|
2257
|
+
logger$a.info(`${msiName$1}: Unavailable. Multiple scopes are not supported.`);
|
|
2258
|
+
return false;
|
|
2259
|
+
}
|
|
2107
2260
|
const result = Boolean(process.env.MSI_ENDPOINT);
|
|
2108
2261
|
if (!result) {
|
|
2109
|
-
logger$
|
|
2262
|
+
logger$a.info(`${msiName$1}: Unavailable. The environment variable MSI_ENDPOINT is needed.`);
|
|
2110
2263
|
}
|
|
2111
2264
|
return result;
|
|
2112
2265
|
},
|
|
2113
|
-
async getToken(
|
|
2114
|
-
|
|
2115
|
-
|
|
2266
|
+
async getToken(configuration, getTokenOptions = {}) {
|
|
2267
|
+
const { identityClient, scopes, clientId } = configuration;
|
|
2268
|
+
logger$a.info(`${msiName$1}: Using the endpoint coming form the environment variable MSI_ENDPOINT = ${process.env.MSI_ENDPOINT}.`);
|
|
2269
|
+
return msiGenericGetToken(identityClient, prepareRequestOptions$1(scopes, clientId), expiresInParser$1, getTokenOptions);
|
|
2116
2270
|
}
|
|
2117
2271
|
};
|
|
2118
2272
|
|
|
2119
2273
|
// Copyright (c) Microsoft Corporation.
|
|
2120
|
-
const
|
|
2121
|
-
|
|
2274
|
+
const msiName$2 = "ManagedIdentityCredential - IMDS";
|
|
2275
|
+
const logger$b = credentialLogger(msiName$2);
|
|
2276
|
+
function expiresInParser$2(requestBody) {
|
|
2122
2277
|
if (requestBody.expires_on) {
|
|
2123
2278
|
// Use the expires_on timestamp if it's available
|
|
2124
2279
|
const expires = +requestBody.expires_on * 1000;
|
|
2125
|
-
logger$
|
|
2280
|
+
logger$b.info(`${msiName$2}: Using expires_on: ${expires} (original value: ${requestBody.expires_on})`);
|
|
2126
2281
|
return expires;
|
|
2127
2282
|
}
|
|
2128
2283
|
else {
|
|
2129
2284
|
// If these aren't possible, use expires_in and calculate a timestamp
|
|
2130
2285
|
const expires = Date.now() + requestBody.expires_in * 1000;
|
|
2131
|
-
logger$
|
|
2286
|
+
logger$b.info(`${msiName$2}: IMDS using expires_in: ${expires} (original value: ${requestBody.expires_in})`);
|
|
2132
2287
|
return expires;
|
|
2133
2288
|
}
|
|
2134
2289
|
}
|
|
2135
|
-
function prepareRequestOptions$
|
|
2290
|
+
function prepareRequestOptions$2(scopes, clientId, options) {
|
|
2136
2291
|
var _a;
|
|
2137
|
-
const
|
|
2138
|
-
|
|
2139
|
-
|
|
2292
|
+
const resource = mapScopesToResource(scopes);
|
|
2293
|
+
if (!resource) {
|
|
2294
|
+
throw new Error(`${msiName$2}: Multiple scopes are not supported.`);
|
|
2295
|
+
}
|
|
2296
|
+
const { skipQuery, skipMetadataHeader } = options || {};
|
|
2297
|
+
let query = "";
|
|
2298
|
+
// Pod Identity will try to process this request even if the Metadata header is missing.
|
|
2299
|
+
// We can exclude the request query to ensure no IMDS endpoint tries to process the ping request.
|
|
2300
|
+
if (!skipQuery) {
|
|
2301
|
+
const queryParameters = {
|
|
2302
|
+
resource,
|
|
2303
|
+
"api-version": imdsApiVersion
|
|
2304
|
+
};
|
|
2305
|
+
if (clientId) {
|
|
2306
|
+
queryParameters.client_id = clientId;
|
|
2307
|
+
}
|
|
2308
|
+
const params = new URLSearchParams(queryParameters);
|
|
2309
|
+
query = `?${params.toString()}`;
|
|
2310
|
+
}
|
|
2311
|
+
const url = new URL(imdsEndpointPath, (_a = process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) !== null && _a !== void 0 ? _a : imdsHost);
|
|
2312
|
+
const rawHeaders = {
|
|
2313
|
+
Accept: "application/json",
|
|
2314
|
+
Metadata: "true"
|
|
2140
2315
|
};
|
|
2141
|
-
|
|
2142
|
-
|
|
2316
|
+
// Remove the Metadata header to invoke a request error from some IMDS endpoints.
|
|
2317
|
+
if (skipMetadataHeader) {
|
|
2318
|
+
delete rawHeaders.Metadata;
|
|
2143
2319
|
}
|
|
2144
2320
|
return {
|
|
2145
|
-
|
|
2321
|
+
// In this case, the `?` should be added in the "query" variable `skipQuery` is not set.
|
|
2322
|
+
url: `${url}${query}`,
|
|
2146
2323
|
method: "GET",
|
|
2147
|
-
|
|
2148
|
-
headers: {
|
|
2149
|
-
Accept: "application/json",
|
|
2150
|
-
Metadata: true
|
|
2151
|
-
}
|
|
2324
|
+
headers: coreRestPipeline.createHttpHeaders(rawHeaders)
|
|
2152
2325
|
};
|
|
2153
2326
|
}
|
|
2154
2327
|
// 800ms -> 1600ms -> 3200ms
|
|
@@ -2158,43 +2331,45 @@ const imdsMsiRetryConfig = {
|
|
|
2158
2331
|
intervalIncrement: 2
|
|
2159
2332
|
};
|
|
2160
2333
|
const imdsMsi = {
|
|
2161
|
-
async isAvailable(
|
|
2162
|
-
var _a, _b
|
|
2163
|
-
const
|
|
2334
|
+
async isAvailable(scopes, identityClient, clientId, getTokenOptions) {
|
|
2335
|
+
var _a, _b;
|
|
2336
|
+
const resource = mapScopesToResource(scopes);
|
|
2337
|
+
if (!resource) {
|
|
2338
|
+
logger$b.info(`${msiName$2}: Unavailable. Multiple scopes are not supported.`);
|
|
2339
|
+
return false;
|
|
2340
|
+
}
|
|
2341
|
+
const { span, updatedOptions: options } = createSpan("ManagedIdentityCredential-pingImdsEndpoint", getTokenOptions);
|
|
2164
2342
|
// if the PodIdenityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist
|
|
2165
|
-
if (process.env.
|
|
2343
|
+
if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) {
|
|
2166
2344
|
return true;
|
|
2167
2345
|
}
|
|
2168
|
-
const
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
delete request.headers.Metadata;
|
|
2174
|
-
}
|
|
2175
|
-
request.spanOptions = (_a = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _a === void 0 ? void 0 : _a.spanOptions;
|
|
2176
|
-
request.tracingContext = (_b = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _b === void 0 ? void 0 : _b.tracingContext;
|
|
2346
|
+
const requestOptions = prepareRequestOptions$2(resource, clientId, {
|
|
2347
|
+
skipMetadataHeader: true,
|
|
2348
|
+
skipQuery: true
|
|
2349
|
+
});
|
|
2350
|
+
requestOptions.tracingOptions = options.tracingOptions;
|
|
2177
2351
|
try {
|
|
2178
2352
|
// Create a request with a timeout since we expect that
|
|
2179
2353
|
// not having a "Metadata" header should cause an error to be
|
|
2180
2354
|
// returned quickly from the endpoint, proving its availability.
|
|
2181
|
-
const
|
|
2182
|
-
|
|
2183
|
-
//
|
|
2184
|
-
|
|
2185
|
-
webResource.timeout = ((_c = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.requestOptions) === null || _c === void 0 ? void 0 : _c.timeout) || 3000;
|
|
2355
|
+
const request = coreRestPipeline.createPipelineRequest(requestOptions);
|
|
2356
|
+
request.timeout = (_b = (_a = options.requestOptions) === null || _a === void 0 ? void 0 : _a.timeout) !== null && _b !== void 0 ? _b : 300;
|
|
2357
|
+
// This MSI uses the imdsEndpoint to get the token, which only uses http://
|
|
2358
|
+
request.allowInsecureConnection = true;
|
|
2186
2359
|
try {
|
|
2187
|
-
|
|
2360
|
+
logger$b.info(`${msiName$2}: Pinging the Azure IMDS endpoint`);
|
|
2361
|
+
await identityClient.sendRequest(request);
|
|
2188
2362
|
}
|
|
2189
2363
|
catch (err) {
|
|
2190
|
-
if ((err.name === "RestError" && err.code ===
|
|
2364
|
+
if ((err.name === "RestError" && err.code === coreRestPipeline.RestError.REQUEST_SEND_ERROR) ||
|
|
2191
2365
|
err.name === "AbortError" ||
|
|
2366
|
+
err.code === "ENETUNREACH" || // Network unreachable
|
|
2192
2367
|
err.code === "ECONNREFUSED" || // connection refused
|
|
2193
2368
|
err.code === "EHOSTDOWN" // host is down
|
|
2194
2369
|
) {
|
|
2195
|
-
// If the request failed, or
|
|
2370
|
+
// If the request failed, or Node.js was unable to establish a connection,
|
|
2196
2371
|
// or the host was down, we'll assume the IMDS endpoint isn't available.
|
|
2197
|
-
logger$
|
|
2372
|
+
logger$b.info(`${msiName$2}: The Azure IMDS endpoint is unavailable`);
|
|
2198
2373
|
span.setStatus({
|
|
2199
2374
|
code: coreTracing.SpanStatusCode.ERROR,
|
|
2200
2375
|
message: err.message
|
|
@@ -2203,14 +2378,13 @@ const imdsMsi = {
|
|
|
2203
2378
|
}
|
|
2204
2379
|
}
|
|
2205
2380
|
// If we received any response, the endpoint is available
|
|
2206
|
-
logger$
|
|
2207
|
-
// IMDS MSI available!
|
|
2381
|
+
logger$b.info(`${msiName$2}: The Azure IMDS endpoint is available`);
|
|
2208
2382
|
return true;
|
|
2209
2383
|
}
|
|
2210
2384
|
catch (err) {
|
|
2211
2385
|
// createWebResource failed.
|
|
2212
2386
|
// This error should bubble up to the user.
|
|
2213
|
-
logger$
|
|
2387
|
+
logger$b.info(`${msiName$2}: Error when creating the WebResource for the Azure IMDS endpoint: ${err.message}`);
|
|
2214
2388
|
span.setStatus({
|
|
2215
2389
|
code: coreTracing.SpanStatusCode.ERROR,
|
|
2216
2390
|
message: err.message
|
|
@@ -2221,88 +2395,58 @@ const imdsMsi = {
|
|
|
2221
2395
|
span.end();
|
|
2222
2396
|
}
|
|
2223
2397
|
},
|
|
2224
|
-
async getToken(
|
|
2225
|
-
|
|
2398
|
+
async getToken(configuration, getTokenOptions = {}) {
|
|
2399
|
+
const { identityClient, scopes, clientId } = configuration;
|
|
2400
|
+
logger$b.info(`${msiName$2}: Using the Azure IMDS endpoint coming from the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the cloud shell to proceed with the authentication.`);
|
|
2226
2401
|
let nextDelayInMs = imdsMsiRetryConfig.startDelayInMs;
|
|
2227
2402
|
for (let retries = 0; retries < imdsMsiRetryConfig.maxRetries; retries++) {
|
|
2228
2403
|
try {
|
|
2229
|
-
return await msiGenericGetToken(identityClient, prepareRequestOptions$
|
|
2404
|
+
return await msiGenericGetToken(identityClient, prepareRequestOptions$2(scopes, clientId), expiresInParser$2, getTokenOptions);
|
|
2230
2405
|
}
|
|
2231
2406
|
catch (error) {
|
|
2232
2407
|
if (error.statusCode === 404) {
|
|
2233
|
-
await
|
|
2408
|
+
await coreUtil.delay(nextDelayInMs);
|
|
2234
2409
|
nextDelayInMs *= imdsMsiRetryConfig.intervalIncrement;
|
|
2235
2410
|
continue;
|
|
2236
2411
|
}
|
|
2237
2412
|
throw error;
|
|
2238
2413
|
}
|
|
2239
2414
|
}
|
|
2240
|
-
throw new AuthenticationError(404,
|
|
2415
|
+
throw new AuthenticationError(404, `${msiName$2}: Failed to retrieve IMDS token after ${imdsMsiRetryConfig.maxRetries} retries.`);
|
|
2241
2416
|
}
|
|
2242
2417
|
};
|
|
2243
2418
|
|
|
2244
2419
|
// Copyright (c) Microsoft Corporation.
|
|
2245
|
-
const
|
|
2246
|
-
|
|
2247
|
-
// Parse a date format like "06/20/2019 02:57:58 +00:00" and
|
|
2248
|
-
// convert it into a JavaScript-formatted date
|
|
2249
|
-
return Date.parse(requestBody.expires_on);
|
|
2250
|
-
}
|
|
2251
|
-
function prepareRequestOptions$2(resource, clientId) {
|
|
2252
|
-
const queryParameters = {
|
|
2253
|
-
resource,
|
|
2254
|
-
"api-version": "2017-09-01"
|
|
2255
|
-
};
|
|
2256
|
-
if (clientId) {
|
|
2257
|
-
queryParameters.clientid = clientId;
|
|
2258
|
-
}
|
|
2259
|
-
return {
|
|
2260
|
-
url: process.env.MSI_ENDPOINT,
|
|
2261
|
-
method: "GET",
|
|
2262
|
-
queryParameters,
|
|
2263
|
-
headers: {
|
|
2264
|
-
Accept: "application/json",
|
|
2265
|
-
secret: process.env.MSI_SECRET
|
|
2266
|
-
}
|
|
2267
|
-
};
|
|
2268
|
-
}
|
|
2269
|
-
const appServiceMsi2017 = {
|
|
2270
|
-
async isAvailable() {
|
|
2271
|
-
const env = process.env;
|
|
2272
|
-
const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);
|
|
2273
|
-
if (!result) {
|
|
2274
|
-
logger$b.info("The Azure App Service MSI 2017 is unavailable.");
|
|
2275
|
-
}
|
|
2276
|
-
return result;
|
|
2277
|
-
},
|
|
2278
|
-
async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
|
|
2279
|
-
logger$b.info(`Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`);
|
|
2280
|
-
return msiGenericGetToken(identityClient, prepareRequestOptions$2(resource, clientId), expiresInParser$2, getTokenOptions);
|
|
2281
|
-
}
|
|
2282
|
-
};
|
|
2283
|
-
|
|
2284
|
-
// Copyright (c) Microsoft Corporation.
|
|
2285
|
-
const logger$c = credentialLogger("ManagedIdentityCredential - ArcMSI");
|
|
2420
|
+
const msiName$3 = "ManagedIdentityCredential - Azure Arc MSI";
|
|
2421
|
+
const logger$c = credentialLogger(msiName$3);
|
|
2286
2422
|
// Azure Arc MSI doesn't have a special expiresIn parser.
|
|
2287
2423
|
const expiresInParser$3 = undefined;
|
|
2288
|
-
function prepareRequestOptions$3(
|
|
2424
|
+
function prepareRequestOptions$3(scopes) {
|
|
2425
|
+
const resource = mapScopesToResource(scopes);
|
|
2426
|
+
if (!resource) {
|
|
2427
|
+
throw new Error(`${msiName$3}: Multiple scopes are not supported.`);
|
|
2428
|
+
}
|
|
2289
2429
|
const queryParameters = {
|
|
2290
2430
|
resource,
|
|
2291
2431
|
"api-version": azureArcAPIVersion
|
|
2292
2432
|
};
|
|
2293
|
-
|
|
2433
|
+
const query = new URLSearchParams(queryParameters);
|
|
2434
|
+
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
2435
|
+
if (!process.env.IDENTITY_ENDPOINT) {
|
|
2436
|
+
throw new Error(`${msiName$3}: Missing environment variable: IDENTITY_ENDPOINT`);
|
|
2437
|
+
}
|
|
2438
|
+
return coreRestPipeline.createPipelineRequest({
|
|
2294
2439
|
// Should be similar to: http://localhost:40342/metadata/identity/oauth2/token
|
|
2295
|
-
url: process.env.IDENTITY_ENDPOINT
|
|
2440
|
+
url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,
|
|
2296
2441
|
method: "GET",
|
|
2297
|
-
|
|
2298
|
-
headers: {
|
|
2442
|
+
headers: coreRestPipeline.createHttpHeaders({
|
|
2299
2443
|
Accept: "application/json",
|
|
2300
|
-
Metadata: true
|
|
2301
|
-
}
|
|
2302
|
-
};
|
|
2444
|
+
Metadata: "true"
|
|
2445
|
+
})
|
|
2446
|
+
});
|
|
2303
2447
|
}
|
|
2304
2448
|
// Since "fs"'s readFileSync locks the thread, and to avoid extra dependencies.
|
|
2305
|
-
function readFileAsync(path, options) {
|
|
2449
|
+
function readFileAsync$1(path, options) {
|
|
2306
2450
|
return new Promise((resolve, reject) => fs.readFile(path, options, (err, data) => {
|
|
2307
2451
|
if (err) {
|
|
2308
2452
|
reject(err);
|
|
@@ -2311,43 +2455,207 @@ function readFileAsync(path, options) {
|
|
|
2311
2455
|
}));
|
|
2312
2456
|
}
|
|
2313
2457
|
async function filePathRequest(identityClient, requestPrepareOptions) {
|
|
2314
|
-
const response = await identityClient.sendRequest(
|
|
2458
|
+
const response = await identityClient.sendRequest(coreRestPipeline.createPipelineRequest(requestPrepareOptions));
|
|
2315
2459
|
if (response.status !== 401) {
|
|
2316
2460
|
let message = "";
|
|
2317
2461
|
if (response.bodyAsText) {
|
|
2318
2462
|
message = ` Response: ${response.bodyAsText}`;
|
|
2319
2463
|
}
|
|
2320
|
-
throw new AuthenticationError(response.status,
|
|
2464
|
+
throw new AuthenticationError(response.status, `${msiName$3}: To authenticate with Azure Arc MSI, status code 401 is expected on the first request. ${message}`);
|
|
2321
2465
|
}
|
|
2322
2466
|
const authHeader = response.headers.get("www-authenticate") || "";
|
|
2323
|
-
|
|
2467
|
+
try {
|
|
2468
|
+
return authHeader.split("=").slice(1)[0];
|
|
2469
|
+
}
|
|
2470
|
+
catch (e) {
|
|
2471
|
+
throw Error(`Invalid www-authenticate header format: ${authHeader}`);
|
|
2472
|
+
}
|
|
2324
2473
|
}
|
|
2325
2474
|
const arcMsi = {
|
|
2326
|
-
async isAvailable() {
|
|
2475
|
+
async isAvailable(scopes) {
|
|
2476
|
+
const resource = mapScopesToResource(scopes);
|
|
2477
|
+
if (!resource) {
|
|
2478
|
+
logger$c.info(`${msiName$3}: Unavailable. Multiple scopes are not supported.`);
|
|
2479
|
+
return false;
|
|
2480
|
+
}
|
|
2327
2481
|
const result = Boolean(process.env.IMDS_ENDPOINT && process.env.IDENTITY_ENDPOINT);
|
|
2328
2482
|
if (!result) {
|
|
2329
|
-
logger$c.info(
|
|
2483
|
+
logger$c.info(`${msiName$3}: The environment variables needed are: IMDS_ENDPOINT and IDENTITY_ENDPOINT`);
|
|
2330
2484
|
}
|
|
2331
2485
|
return result;
|
|
2332
2486
|
},
|
|
2333
|
-
async getToken(
|
|
2334
|
-
|
|
2487
|
+
async getToken(configuration, getTokenOptions = {}) {
|
|
2488
|
+
var _a;
|
|
2489
|
+
const { identityClient, scopes, clientId } = configuration;
|
|
2490
|
+
logger$c.info(`${msiName$3}: Authenticating.`);
|
|
2335
2491
|
if (clientId) {
|
|
2336
|
-
throw new Error(
|
|
2492
|
+
throw new Error(`${msiName$3}: User assigned identity is not supported by the Azure Arc Managed Identity Endpoint. To authenticate with the system assigned identity, omit the client id when constructing the ManagedIdentityCredential, or if authenticating with the DefaultAzureCredential ensure the AZURE_CLIENT_ID environment variable is not set.`);
|
|
2337
2493
|
}
|
|
2338
|
-
const requestOptions = Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal
|
|
2494
|
+
const requestOptions = Object.assign(Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$3(scopes)), { allowInsecureConnection: true });
|
|
2339
2495
|
const filePath = await filePathRequest(identityClient, requestOptions);
|
|
2340
2496
|
if (!filePath) {
|
|
2341
|
-
throw new Error(
|
|
2497
|
+
throw new Error(`${msiName$3}: Failed to find the token file.`);
|
|
2342
2498
|
}
|
|
2343
|
-
const key = await readFileAsync(filePath, { encoding: "utf-8" });
|
|
2344
|
-
requestOptions.headers
|
|
2499
|
+
const key = await readFileAsync$1(filePath, { encoding: "utf-8" });
|
|
2500
|
+
(_a = requestOptions.headers) === null || _a === void 0 ? void 0 : _a.set("Authorization", `Basic ${key}`);
|
|
2345
2501
|
return msiGenericGetToken(identityClient, requestOptions, expiresInParser$3, getTokenOptions);
|
|
2346
2502
|
}
|
|
2347
2503
|
};
|
|
2348
2504
|
|
|
2349
2505
|
// Copyright (c) Microsoft Corporation.
|
|
2350
|
-
const
|
|
2506
|
+
const msiName$4 = "ManagedIdentityCredential - Token Exchange";
|
|
2507
|
+
const logger$d = credentialLogger(msiName$4);
|
|
2508
|
+
const readFileAsync$2 = util.promisify(fs__default.readFile);
|
|
2509
|
+
function expiresInParser$4(requestBody) {
|
|
2510
|
+
// Parses a string representation of the seconds since epoch into a number value
|
|
2511
|
+
return Number(requestBody.expires_on);
|
|
2512
|
+
}
|
|
2513
|
+
function prepareRequestOptions$4(scopes, clientAssertion, clientId) {
|
|
2514
|
+
var _a;
|
|
2515
|
+
const bodyParams = {
|
|
2516
|
+
scope: Array.isArray(scopes) ? scopes.join(" ") : scopes,
|
|
2517
|
+
client_assertion: clientAssertion,
|
|
2518
|
+
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
|
|
2519
|
+
client_id: clientId,
|
|
2520
|
+
grant_type: "client_credentials"
|
|
2521
|
+
};
|
|
2522
|
+
const urlParams = new URLSearchParams(bodyParams);
|
|
2523
|
+
const url = new URL(`${process.env.AZURE_TENANT_ID}/oauth2/v2.0/token`, (_a = process.env.AZURE_AUTHORITY_HOST) !== null && _a !== void 0 ? _a : DefaultAuthorityHost);
|
|
2524
|
+
return {
|
|
2525
|
+
url: url.toString(),
|
|
2526
|
+
method: "POST",
|
|
2527
|
+
body: urlParams.toString(),
|
|
2528
|
+
headers: coreRestPipeline.createHttpHeaders({
|
|
2529
|
+
Accept: "application/json"
|
|
2530
|
+
})
|
|
2531
|
+
};
|
|
2532
|
+
}
|
|
2533
|
+
function tokenExchangeMsi() {
|
|
2534
|
+
const azureFederatedTokenFilePath = process.env.AZURE_FEDERATED_TOKEN_FILE;
|
|
2535
|
+
let azureFederatedTokenFileContent = undefined;
|
|
2536
|
+
let cacheDate = undefined;
|
|
2537
|
+
// Only reads from the assertion file once every 5 minutes
|
|
2538
|
+
async function readAssertion() {
|
|
2539
|
+
// Cached assertions expire after 5 minutes
|
|
2540
|
+
if (cacheDate !== undefined && Date.now() - cacheDate >= 1000 * 60 * 5) {
|
|
2541
|
+
azureFederatedTokenFileContent = undefined;
|
|
2542
|
+
}
|
|
2543
|
+
if (!azureFederatedTokenFileContent) {
|
|
2544
|
+
const file = await readFileAsync$2(azureFederatedTokenFilePath, "utf8");
|
|
2545
|
+
const value = file.trim();
|
|
2546
|
+
if (!value) {
|
|
2547
|
+
throw new Error(`No content on the file ${azureFederatedTokenFilePath}, indicated by the environment variable AZURE_FEDERATED_TOKEN_FILE`);
|
|
2548
|
+
}
|
|
2549
|
+
else {
|
|
2550
|
+
azureFederatedTokenFileContent = value;
|
|
2551
|
+
cacheDate = Date.now();
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
return azureFederatedTokenFileContent;
|
|
2555
|
+
}
|
|
2556
|
+
return {
|
|
2557
|
+
async isAvailable(_scopes, _identityClient, clientId) {
|
|
2558
|
+
const env = process.env;
|
|
2559
|
+
const result = Boolean((clientId || env.AZURE_CLIENT_ID) && env.AZURE_TENANT_ID && azureFederatedTokenFilePath);
|
|
2560
|
+
if (!result) {
|
|
2561
|
+
logger$d.info(`${msiName$4}: Unavailable. The environment variables needed are: AZURE_CLIENT_ID (or the client ID sent through the parameters), AZURE_TENANT_ID and AZURE_FEDERATED_TOKEN_FILE`);
|
|
2562
|
+
}
|
|
2563
|
+
return result;
|
|
2564
|
+
},
|
|
2565
|
+
async getToken(configuration, getTokenOptions = {}) {
|
|
2566
|
+
const { identityClient, scopes, clientId } = configuration;
|
|
2567
|
+
logger$d.info(`${msiName$4}: Using the client assertion coming from environment variables.`);
|
|
2568
|
+
let assertion;
|
|
2569
|
+
try {
|
|
2570
|
+
assertion = await readAssertion();
|
|
2571
|
+
}
|
|
2572
|
+
catch (err) {
|
|
2573
|
+
throw new Error(`${msiName$4}: Failed to read ${azureFederatedTokenFilePath}, indicated by the environment variable AZURE_FEDERATED_TOKEN_FILE`);
|
|
2574
|
+
}
|
|
2575
|
+
return msiGenericGetToken(identityClient, prepareRequestOptions$4(scopes, assertion, clientId || process.env.AZURE_CLIENT_ID), expiresInParser$4, getTokenOptions);
|
|
2576
|
+
}
|
|
2577
|
+
};
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2580
|
+
// Copyright (c) Microsoft Corporation.
|
|
2581
|
+
const msiName$5 = "ManagedIdentityCredential - Fabric MSI";
|
|
2582
|
+
const logger$e = credentialLogger(msiName$5);
|
|
2583
|
+
function expiresInParser$5(requestBody) {
|
|
2584
|
+
// Parses a string representation of the seconds since epoch into a number value
|
|
2585
|
+
return Number(requestBody.expires_on);
|
|
2586
|
+
}
|
|
2587
|
+
function prepareRequestOptions$5(scopes, clientId) {
|
|
2588
|
+
const resource = mapScopesToResource(scopes);
|
|
2589
|
+
if (!resource) {
|
|
2590
|
+
throw new Error(`${msiName$5}: Multiple scopes are not supported.`);
|
|
2591
|
+
}
|
|
2592
|
+
const queryParameters = {
|
|
2593
|
+
resource,
|
|
2594
|
+
"api-version": azureFabricVersion
|
|
2595
|
+
};
|
|
2596
|
+
if (clientId) {
|
|
2597
|
+
queryParameters.client_id = clientId;
|
|
2598
|
+
}
|
|
2599
|
+
const query = new URLSearchParams(queryParameters);
|
|
2600
|
+
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
2601
|
+
if (!process.env.IDENTITY_ENDPOINT) {
|
|
2602
|
+
throw new Error("Missing environment variable: IDENTITY_ENDPOINT");
|
|
2603
|
+
}
|
|
2604
|
+
if (!process.env.IDENTITY_HEADER) {
|
|
2605
|
+
throw new Error("Missing environment variable: IDENTITY_HEADER");
|
|
2606
|
+
}
|
|
2607
|
+
return {
|
|
2608
|
+
url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,
|
|
2609
|
+
method: "GET",
|
|
2610
|
+
headers: coreRestPipeline.createHttpHeaders({
|
|
2611
|
+
Accept: "application/json",
|
|
2612
|
+
Secret: process.env.IDENTITY_HEADER
|
|
2613
|
+
})
|
|
2614
|
+
};
|
|
2615
|
+
}
|
|
2616
|
+
// This credential can be easily tested by deploying a container to Azure Service Fabric with the Dockerfile:
|
|
2617
|
+
//
|
|
2618
|
+
// FROM node:12
|
|
2619
|
+
// RUN wget https://host.any/path/bash.sh
|
|
2620
|
+
// CMD ["bash", "bash.sh"]
|
|
2621
|
+
//
|
|
2622
|
+
// Where the bash script contains:
|
|
2623
|
+
//
|
|
2624
|
+
// curl --insecure $IDENTITY_ENDPOINT'?api-version=2019-07-01-preview&resource=https://vault.azure.net/' -H "Secret: $IDENTITY_HEADER"
|
|
2625
|
+
//
|
|
2626
|
+
const fabricMsi = {
|
|
2627
|
+
async isAvailable(scopes) {
|
|
2628
|
+
const resource = mapScopesToResource(scopes);
|
|
2629
|
+
if (!resource) {
|
|
2630
|
+
logger$e.info(`${msiName$5}: Unavailable. Multiple scopes are not supported.`);
|
|
2631
|
+
return false;
|
|
2632
|
+
}
|
|
2633
|
+
const env = process.env;
|
|
2634
|
+
const result = Boolean(env.IDENTITY_ENDPOINT && env.IDENTITY_HEADER && env.IDENTITY_SERVER_THUMBPRINT);
|
|
2635
|
+
if (!result) {
|
|
2636
|
+
logger$e.info(`${msiName$5}: Unavailable. The environment variables needed are: IDENTITY_ENDPOINT, IDENTITY_HEADER and IDENTITY_SERVER_THUMBPRINT`);
|
|
2637
|
+
}
|
|
2638
|
+
return result;
|
|
2639
|
+
},
|
|
2640
|
+
async getToken(configuration, getTokenOptions = {}) {
|
|
2641
|
+
const { scopes, identityClient, clientId } = configuration;
|
|
2642
|
+
logger$e.info([
|
|
2643
|
+
`${msiName$5}:`,
|
|
2644
|
+
"Using the endpoint and the secret coming from the environment variables:",
|
|
2645
|
+
`IDENTITY_ENDPOINT=${process.env.IDENTITY_ENDPOINT},`,
|
|
2646
|
+
"IDENTITY_HEADER=[REDACTED] and",
|
|
2647
|
+
"IDENTITY_SERVER_THUMBPRINT=[REDACTED]."
|
|
2648
|
+
].join(" "));
|
|
2649
|
+
return msiGenericGetToken(identityClient, prepareRequestOptions$5(scopes, clientId), expiresInParser$5, getTokenOptions, new https.Agent({
|
|
2650
|
+
// This is necessary because Service Fabric provides a self-signed certificate.
|
|
2651
|
+
// The alternative path is to verify the certificate using the IDENTITY_SERVER_THUMBPRINT env variable.
|
|
2652
|
+
rejectUnauthorized: false
|
|
2653
|
+
}));
|
|
2654
|
+
}
|
|
2655
|
+
};
|
|
2656
|
+
|
|
2657
|
+
// Copyright (c) Microsoft Corporation.
|
|
2658
|
+
const logger$f = credentialLogger("ManagedIdentityCredential");
|
|
2351
2659
|
/**
|
|
2352
2660
|
* Attempts authentication using a managed identity that has been assigned
|
|
2353
2661
|
* to the deployment environment. This authentication type works in Azure VMs,
|
|
@@ -2374,15 +2682,13 @@ class ManagedIdentityCredential {
|
|
|
2374
2682
|
this.identityClient = new IdentityClient(clientIdOrOptions);
|
|
2375
2683
|
}
|
|
2376
2684
|
}
|
|
2377
|
-
async cachedAvailableMSI(
|
|
2685
|
+
async cachedAvailableMSI(scopes, clientId, getTokenOptions) {
|
|
2378
2686
|
if (this.cachedMSI) {
|
|
2379
2687
|
return this.cachedMSI;
|
|
2380
2688
|
}
|
|
2381
|
-
|
|
2382
|
-
// which is necessary since Service Fabric only provides self-signed certificates on their Identity Endpoint.
|
|
2383
|
-
const MSIs = [appServiceMsi2017, cloudShellMsi, arcMsi, imdsMsi];
|
|
2689
|
+
const MSIs = [fabricMsi, appServiceMsi2017, cloudShellMsi, arcMsi, tokenExchangeMsi(), imdsMsi];
|
|
2384
2690
|
for (const msi of MSIs) {
|
|
2385
|
-
if (await msi.isAvailable(this.identityClient,
|
|
2691
|
+
if (await msi.isAvailable(scopes, this.identityClient, clientId, getTokenOptions)) {
|
|
2386
2692
|
this.cachedMSI = msi;
|
|
2387
2693
|
return msi;
|
|
2388
2694
|
}
|
|
@@ -2390,12 +2696,15 @@ class ManagedIdentityCredential {
|
|
|
2390
2696
|
throw new CredentialUnavailableError("ManagedIdentityCredential - No MSI credential available");
|
|
2391
2697
|
}
|
|
2392
2698
|
async authenticateManagedIdentity(scopes, clientId, getTokenOptions) {
|
|
2393
|
-
const resource = mapScopesToResource(scopes);
|
|
2394
2699
|
const { span, updatedOptions } = createSpan("ManagedIdentityCredential-authenticateManagedIdentity", getTokenOptions);
|
|
2395
2700
|
try {
|
|
2396
2701
|
// Determining the available MSI, and avoiding checking for other MSIs while the program is running.
|
|
2397
|
-
const availableMSI = await this.cachedAvailableMSI(
|
|
2398
|
-
return availableMSI.getToken(
|
|
2702
|
+
const availableMSI = await this.cachedAvailableMSI(scopes, clientId, updatedOptions);
|
|
2703
|
+
return availableMSI.getToken({
|
|
2704
|
+
identityClient: this.identityClient,
|
|
2705
|
+
scopes,
|
|
2706
|
+
clientId
|
|
2707
|
+
}, updatedOptions);
|
|
2399
2708
|
}
|
|
2400
2709
|
catch (err) {
|
|
2401
2710
|
span.setStatus({
|
|
@@ -2419,7 +2728,7 @@ class ManagedIdentityCredential {
|
|
|
2419
2728
|
*/
|
|
2420
2729
|
async getToken(scopes, options) {
|
|
2421
2730
|
let result = null;
|
|
2422
|
-
const { span, updatedOptions } = createSpan("ManagedIdentityCredential
|
|
2731
|
+
const { span, updatedOptions } = createSpan("ManagedIdentityCredential.getToken", options);
|
|
2423
2732
|
try {
|
|
2424
2733
|
// isEndpointAvailable can be true, false, or null,
|
|
2425
2734
|
// If it's null, it means we don't yet know whether
|
|
@@ -2434,7 +2743,7 @@ class ManagedIdentityCredential {
|
|
|
2434
2743
|
// It also means that the endpoint answered with either 200 or 201 (see the sendTokenRequest method),
|
|
2435
2744
|
// yet we had no access token. For this reason, we'll throw once with a specific message:
|
|
2436
2745
|
const error = new CredentialUnavailableError("The managed identity endpoint was reached, yet no tokens were received.");
|
|
2437
|
-
logger$
|
|
2746
|
+
logger$f.getToken.info(formatError(scopes, error));
|
|
2438
2747
|
throw error;
|
|
2439
2748
|
}
|
|
2440
2749
|
// Since `authenticateManagedIdentity` didn't throw, and the result was not null,
|
|
@@ -2446,10 +2755,10 @@ class ManagedIdentityCredential {
|
|
|
2446
2755
|
// We've previously determined that the endpoint was unavailable,
|
|
2447
2756
|
// either because it was unreachable or permanently unable to authenticate.
|
|
2448
2757
|
const error = new CredentialUnavailableError("The managed identity endpoint is not currently available");
|
|
2449
|
-
logger$
|
|
2758
|
+
logger$f.getToken.info(formatError(scopes, error));
|
|
2450
2759
|
throw error;
|
|
2451
2760
|
}
|
|
2452
|
-
logger$
|
|
2761
|
+
logger$f.getToken.info(formatSuccess(scopes));
|
|
2453
2762
|
return result;
|
|
2454
2763
|
}
|
|
2455
2764
|
catch (err) {
|
|
@@ -2470,21 +2779,21 @@ class ManagedIdentityCredential {
|
|
|
2470
2779
|
// If either the network is unreachable,
|
|
2471
2780
|
// we can safely assume the credential is unavailable.
|
|
2472
2781
|
if (err.code === "ENETUNREACH") {
|
|
2473
|
-
const error = new CredentialUnavailableError(
|
|
2474
|
-
logger$
|
|
2782
|
+
const error = new CredentialUnavailableError(`ManagedIdentityCredential is unavailable. Network unreachable. Message: ${err.message}`);
|
|
2783
|
+
logger$f.getToken.info(formatError(scopes, error));
|
|
2475
2784
|
throw error;
|
|
2476
2785
|
}
|
|
2477
2786
|
// If either the host was unreachable,
|
|
2478
2787
|
// we can safely assume the credential is unavailable.
|
|
2479
2788
|
if (err.code === "EHOSTUNREACH") {
|
|
2480
|
-
const error = new CredentialUnavailableError(
|
|
2481
|
-
logger$
|
|
2789
|
+
const error = new CredentialUnavailableError(`ManagedIdentityCredential is unavailable. No managed identity endpoint found. Message: ${err.message}`);
|
|
2790
|
+
logger$f.getToken.info(formatError(scopes, error));
|
|
2482
2791
|
throw error;
|
|
2483
2792
|
}
|
|
2484
2793
|
// If err.statusCode has a value of 400, it comes from sendTokenRequest,
|
|
2485
2794
|
// and it means that the endpoint is working, but that no identity is available.
|
|
2486
2795
|
if (err.statusCode === 400) {
|
|
2487
|
-
throw new CredentialUnavailableError(
|
|
2796
|
+
throw new CredentialUnavailableError(`ManagedIdentityCredential: The managed identity endpoint is indicating there's no available identity. Message: ${err.message}`);
|
|
2488
2797
|
}
|
|
2489
2798
|
// If the error has no status code, we can assume there was no available identity.
|
|
2490
2799
|
// This will throw silently during any ChainedTokenCredential.
|
|
@@ -2532,36 +2841,37 @@ const defaultCredentials = [
|
|
|
2532
2841
|
];
|
|
2533
2842
|
/**
|
|
2534
2843
|
* Provides a default {@link ChainedTokenCredential} configuration that should
|
|
2535
|
-
* work for most applications that use the Azure SDK.
|
|
2536
|
-
* types will be tried, in order:
|
|
2537
|
-
*
|
|
2538
|
-
* - {@link EnvironmentCredential}
|
|
2539
|
-
* - {@link ManagedIdentityCredential}
|
|
2540
|
-
* - {@link VisualStudioCodeCredential}
|
|
2541
|
-
* - {@link AzureCliCredential}
|
|
2542
|
-
* - {@link AzurePowerShellCredential}
|
|
2543
|
-
*
|
|
2544
|
-
* Consult the documentation of these credential types for more information
|
|
2545
|
-
* on how they attempt authentication.
|
|
2546
|
-
*
|
|
2547
|
-
* **Note**: `VisualStudioCodeCredential` is provided by an extension package:
|
|
2548
|
-
* `@azure/identity-vscode`. If this package is not installed and registered
|
|
2549
|
-
* using the extension API (`useIdentityExtension`), then authentication using
|
|
2550
|
-
* `VisualStudioCodeCredential` will not be available.
|
|
2551
|
-
*
|
|
2552
|
-
* Azure Identity extensions may add credential types to the default credential
|
|
2553
|
-
* stack.
|
|
2844
|
+
* work for most applications that use the Azure SDK.
|
|
2554
2845
|
*/
|
|
2555
2846
|
class DefaultAzureCredential extends ChainedTokenCredential {
|
|
2556
2847
|
/**
|
|
2557
2848
|
* Creates an instance of the DefaultAzureCredential class.
|
|
2558
2849
|
*
|
|
2850
|
+
* This credential provides a default {@link ChainedTokenCredential} configuration that should
|
|
2851
|
+
* work for most applications that use the Azure SDK.
|
|
2852
|
+
*
|
|
2853
|
+
* The following credential types will be tried, in order:
|
|
2854
|
+
*
|
|
2855
|
+
* - {@link EnvironmentCredential}
|
|
2856
|
+
* - {@link ManagedIdentityCredential}
|
|
2857
|
+
* - {@link VisualStudioCodeCredential}
|
|
2858
|
+
* - {@link AzureCliCredential}
|
|
2859
|
+
* - {@link AzurePowerShellCredential}
|
|
2860
|
+
*
|
|
2861
|
+
* Consult the documentation of these credential types for more information
|
|
2862
|
+
* on how they attempt authentication.
|
|
2863
|
+
*
|
|
2864
|
+
* **Note**: `VisualStudioCodeCredential` is provided by a plugin package:
|
|
2865
|
+
* `@azure/identity-vscode`. If this package is not installed and registered
|
|
2866
|
+
* using the plugin API (`useIdentityPlugin`), then authentication using
|
|
2867
|
+
* `VisualStudioCodeCredential` will not be available.
|
|
2868
|
+
*
|
|
2559
2869
|
* @param options - Optional parameters. See {@link DefaultAzureCredentialOptions}.
|
|
2560
2870
|
*/
|
|
2561
2871
|
constructor(options) {
|
|
2562
2872
|
super(...defaultCredentials.map((ctor) => new ctor(options)));
|
|
2563
2873
|
this.UnavailableMessage =
|
|
2564
|
-
"DefaultAzureCredential => failed to retrieve a token from the included credentials";
|
|
2874
|
+
"DefaultAzureCredential => failed to retrieve a token from the included credentials. To troubleshoot, visit https://aka.ms/azsdk/js/identity/defaultazurecredential/troubleshoot.";
|
|
2565
2875
|
}
|
|
2566
2876
|
}
|
|
2567
2877
|
|
|
@@ -2581,7 +2891,7 @@ const interactiveBrowserMockable = {
|
|
|
2581
2891
|
class MsalOpenBrowser extends MsalNode {
|
|
2582
2892
|
constructor(options) {
|
|
2583
2893
|
super(options);
|
|
2584
|
-
this.logger = credentialLogger("
|
|
2894
|
+
this.logger = credentialLogger("Node.js MSAL Open Browser");
|
|
2585
2895
|
this.redirectUri = options.redirectUri;
|
|
2586
2896
|
this.loginHint = options.loginHint;
|
|
2587
2897
|
const url = new URL(this.redirectUri);
|
|
@@ -2709,29 +3019,29 @@ class MsalOpenBrowser extends MsalNode {
|
|
|
2709
3019
|
}
|
|
2710
3020
|
|
|
2711
3021
|
// Copyright (c) Microsoft Corporation.
|
|
2712
|
-
const logger$
|
|
3022
|
+
const logger$g = credentialLogger("InteractiveBrowserCredential");
|
|
2713
3023
|
/**
|
|
2714
3024
|
* Enables authentication to Azure Active Directory inside of the web browser
|
|
2715
3025
|
* using the interactive login flow.
|
|
2716
|
-
*
|
|
2717
|
-
* This credential uses the [Authorization Code Flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-auth-code-flow).
|
|
2718
|
-
* On NodeJS, it will open a browser window while it listens for a redirect response from the authentication service.
|
|
2719
|
-
* On browsers, it authenticates via popups. The `loginStyle` optional parameter can be set to `redirect` to authenticate by redirecting the user to an Azure secure login page, which then will redirect the user back to the web application where the authentication started.
|
|
2720
|
-
*
|
|
2721
|
-
* For Node.js, if a `clientId` is provided, the Azure Active Directory application will need to be configured to have a "Mobile and desktop applications" redirect endpoint.
|
|
2722
|
-
* Follow our guide on [setting up Redirect URIs for Desktop apps that calls to web APIs](https://docs.microsoft.com/azure/active-directory/develop/scenario-desktop-app-registration#redirect-uris).
|
|
2723
3026
|
*/
|
|
2724
3027
|
class InteractiveBrowserCredential {
|
|
2725
3028
|
/**
|
|
2726
3029
|
* Creates an instance of InteractiveBrowserCredential with the details needed.
|
|
2727
3030
|
*
|
|
3031
|
+
* This credential uses the [Authorization Code Flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-auth-code-flow).
|
|
3032
|
+
* On Node.js, it will open a browser window while it listens for a redirect response from the authentication service.
|
|
3033
|
+
* On browsers, it authenticates via popups. The `loginStyle` optional parameter can be set to `redirect` to authenticate by redirecting the user to an Azure secure login page, which then will redirect the user back to the web application where the authentication started.
|
|
3034
|
+
*
|
|
3035
|
+
* For Node.js, if a `clientId` is provided, the Azure Active Directory application will need to be configured to have a "Mobile and desktop applications" redirect endpoint.
|
|
3036
|
+
* Follow our guide on [setting up Redirect URIs for Desktop apps that calls to web APIs](https://docs.microsoft.com/azure/active-directory/develop/scenario-desktop-app-registration#redirect-uris).
|
|
3037
|
+
*
|
|
2728
3038
|
* @param options - Options for configuring the client which makes the authentication requests.
|
|
2729
3039
|
*/
|
|
2730
3040
|
constructor(options = {}) {
|
|
2731
3041
|
const redirectUri = typeof options.redirectUri === "function"
|
|
2732
3042
|
? options.redirectUri()
|
|
2733
3043
|
: options.redirectUri || "http://localhost";
|
|
2734
|
-
this.msalFlow = new MsalOpenBrowser(Object.assign(Object.assign({}, options), { tokenCredentialOptions: options, logger: logger$
|
|
3044
|
+
this.msalFlow = new MsalOpenBrowser(Object.assign(Object.assign({}, options), { tokenCredentialOptions: options, logger: logger$g,
|
|
2735
3045
|
redirectUri }));
|
|
2736
3046
|
this.disableAutomaticAuthentication = options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication;
|
|
2737
3047
|
}
|
|
@@ -2809,7 +3119,7 @@ class MsalDeviceCode extends MsalNode {
|
|
|
2809
3119
|
}
|
|
2810
3120
|
|
|
2811
3121
|
// Copyright (c) Microsoft Corporation.
|
|
2812
|
-
const logger$
|
|
3122
|
+
const logger$h = credentialLogger("DeviceCodeCredential");
|
|
2813
3123
|
/**
|
|
2814
3124
|
* Method that logs the user code from the DeviceCodeCredential.
|
|
2815
3125
|
* @param deviceCodeInfo - The device code.
|
|
@@ -2826,10 +3136,24 @@ class DeviceCodeCredential {
|
|
|
2826
3136
|
* Creates an instance of DeviceCodeCredential with the details needed
|
|
2827
3137
|
* to initiate the device code authorization flow with Azure Active Directory.
|
|
2828
3138
|
*
|
|
3139
|
+
* A message will be logged, giving users a code that they can use to authenticate once they go to https://microsoft.com/devicelogin
|
|
3140
|
+
*
|
|
3141
|
+
* Developers can configure how this message is shown by passing a custom `userPromptCallback`:
|
|
3142
|
+
*
|
|
3143
|
+
* ```js
|
|
3144
|
+
* const credential = new DeviceCodeCredential({
|
|
3145
|
+
* tenantId: env.AZURE_TENANT_ID,
|
|
3146
|
+
* clientId: env.AZURE_CLIENT_ID,
|
|
3147
|
+
* userPromptCallback: (info) => {
|
|
3148
|
+
* console.log("CUSTOMIZED PROMPT CALLBACK", info.message);
|
|
3149
|
+
* }
|
|
3150
|
+
* });
|
|
3151
|
+
* ```
|
|
3152
|
+
*
|
|
2829
3153
|
* @param options - Options for configuring the client which makes the authentication requests.
|
|
2830
3154
|
*/
|
|
2831
3155
|
constructor(options) {
|
|
2832
|
-
this.msalFlow = new MsalDeviceCode(Object.assign(Object.assign({}, options), { logger: logger$
|
|
3156
|
+
this.msalFlow = new MsalDeviceCode(Object.assign(Object.assign({}, options), { logger: logger$h, userPromptCallback: (options === null || options === void 0 ? void 0 : options.userPromptCallback) || defaultDeviceCodePromptCallback, tokenCredentialOptions: options || {} }));
|
|
2833
3157
|
this.disableAutomaticAuthentication = options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication;
|
|
2834
3158
|
}
|
|
2835
3159
|
/**
|
|
@@ -2870,7 +3194,45 @@ class DeviceCodeCredential {
|
|
|
2870
3194
|
}
|
|
2871
3195
|
|
|
2872
3196
|
// Copyright (c) Microsoft Corporation.
|
|
2873
|
-
|
|
3197
|
+
/**
|
|
3198
|
+
* This MSAL client sets up a web server to listen for redirect callbacks, then calls to the MSAL's public application's `acquireTokenByDeviceCode` during `doGetToken`
|
|
3199
|
+
* to trigger the authentication flow, and then respond based on the values obtained from the redirect callback
|
|
3200
|
+
* @internal
|
|
3201
|
+
*/
|
|
3202
|
+
class MsalAuthorizationCode extends MsalNode {
|
|
3203
|
+
constructor(options) {
|
|
3204
|
+
super(options);
|
|
3205
|
+
this.logger = credentialLogger("Node.js MSAL Authorization Code");
|
|
3206
|
+
this.redirectUri = options.redirectUri;
|
|
3207
|
+
this.authorizationCode = options.authorizationCode;
|
|
3208
|
+
if (options.clientSecret) {
|
|
3209
|
+
this.msalConfig.auth.clientSecret = options.clientSecret;
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
async getAuthCodeUrl(options) {
|
|
3213
|
+
await this.init();
|
|
3214
|
+
return this.confidentialApp.getAuthCodeUrl(options);
|
|
3215
|
+
}
|
|
3216
|
+
async doGetToken(scopes, options) {
|
|
3217
|
+
var _a;
|
|
3218
|
+
try {
|
|
3219
|
+
const result = await ((_a = this.confidentialApp) === null || _a === void 0 ? void 0 : _a.acquireTokenByCode({
|
|
3220
|
+
scopes,
|
|
3221
|
+
redirectUri: this.redirectUri,
|
|
3222
|
+
code: this.authorizationCode
|
|
3223
|
+
}));
|
|
3224
|
+
// The Client Credential flow does not return an account,
|
|
3225
|
+
// so each time getToken gets called, we will have to acquire a new token through the service.
|
|
3226
|
+
return this.handleResult(scopes, this.clientId, result || undefined);
|
|
3227
|
+
}
|
|
3228
|
+
catch (err) {
|
|
3229
|
+
throw this.handleError(scopes, err, options);
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
// Copyright (c) Microsoft Corporation.
|
|
3235
|
+
const logger$i = credentialLogger("AuthorizationCodeCredential");
|
|
2874
3236
|
/**
|
|
2875
3237
|
* Enables authentication to Azure Active Directory using an authorization code
|
|
2876
3238
|
* that was obtained through the authorization code flow, described in more detail
|
|
@@ -2884,26 +3246,23 @@ class AuthorizationCodeCredential {
|
|
|
2884
3246
|
* @internal
|
|
2885
3247
|
*/
|
|
2886
3248
|
constructor(tenantId, clientId, clientSecretOrAuthorizationCode, authorizationCodeOrRedirectUri, redirectUriOrOptions, options) {
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
this.clientId = clientId;
|
|
2890
|
-
this.tenantId = tenantId;
|
|
3249
|
+
checkTenantId(logger$i, tenantId);
|
|
3250
|
+
let clientSecret = clientSecretOrAuthorizationCode;
|
|
2891
3251
|
if (typeof redirectUriOrOptions === "string") {
|
|
2892
3252
|
// the clientId+clientSecret constructor
|
|
2893
|
-
this.clientSecret = clientSecretOrAuthorizationCode;
|
|
2894
3253
|
this.authorizationCode = authorizationCodeOrRedirectUri;
|
|
2895
3254
|
this.redirectUri = redirectUriOrOptions;
|
|
2896
3255
|
// options okay
|
|
2897
3256
|
}
|
|
2898
3257
|
else {
|
|
2899
3258
|
// clientId only
|
|
2900
|
-
this.clientSecret = undefined;
|
|
2901
3259
|
this.authorizationCode = clientSecretOrAuthorizationCode;
|
|
2902
3260
|
this.redirectUri = authorizationCodeOrRedirectUri;
|
|
3261
|
+
clientSecret = undefined;
|
|
2903
3262
|
options = redirectUriOrOptions;
|
|
2904
3263
|
}
|
|
2905
|
-
this.
|
|
2906
|
-
|
|
3264
|
+
this.msalFlow = new MsalAuthorizationCode(Object.assign(Object.assign({}, options), { clientSecret,
|
|
3265
|
+
clientId, tokenCredentialOptions: options || {}, logger: logger$i, redirectUri: this.redirectUri, authorizationCode: this.authorizationCode }));
|
|
2907
3266
|
}
|
|
2908
3267
|
/**
|
|
2909
3268
|
* Authenticates with Azure Active Directory and returns an access token if successful.
|
|
@@ -2913,65 +3272,116 @@ class AuthorizationCodeCredential {
|
|
|
2913
3272
|
* @param options - The options used to configure any requests this
|
|
2914
3273
|
* TokenCredential implementation might make.
|
|
2915
3274
|
*/
|
|
2916
|
-
async getToken(scopes, options) {
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
this.
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
},
|
|
2950
|
-
abortSignal: options && options.abortSignal,
|
|
2951
|
-
spanOptions: (_a = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _a === void 0 ? void 0 : _a.spanOptions,
|
|
2952
|
-
tracingContext: (_b = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _b === void 0 ? void 0 : _b.tracingContext
|
|
2953
|
-
});
|
|
2954
|
-
tokenResponse = await this.identityClient.sendTokenRequest(webResource);
|
|
3275
|
+
async getToken(scopes, options = {}) {
|
|
3276
|
+
return trace(`${this.constructor.name}.getToken`, options, async (newOptions) => {
|
|
3277
|
+
const arrayScopes = Array.isArray(scopes) ? scopes : [scopes];
|
|
3278
|
+
return this.msalFlow.getToken(arrayScopes, Object.assign(Object.assign({}, newOptions), { disableAutomaticAuthentication: this.disableAutomaticAuthentication }));
|
|
3279
|
+
});
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3283
|
+
// Copyright (c) Microsoft Corporation.
|
|
3284
|
+
/**
|
|
3285
|
+
* MSAL on behalf of flow. Calls to MSAL's confidential application's `acquireTokenOnBehalfOf` during `doGetToken`.
|
|
3286
|
+
* @internal
|
|
3287
|
+
*/
|
|
3288
|
+
class MsalOnBehalfOf extends MsalNode {
|
|
3289
|
+
constructor(options) {
|
|
3290
|
+
super(options);
|
|
3291
|
+
this.logger.info("Initialized MSAL's On-Behalf-Of flow");
|
|
3292
|
+
this.requiresConfidential = true;
|
|
3293
|
+
this.userAssertionToken = options.userAssertionToken;
|
|
3294
|
+
this.certificatePath = options.certificatePath;
|
|
3295
|
+
this.sendCertificateChain = options.sendCertificateChain;
|
|
3296
|
+
this.clientSecret = options.clientSecret;
|
|
3297
|
+
}
|
|
3298
|
+
// Changing the MSAL configuration asynchronously
|
|
3299
|
+
async init(options) {
|
|
3300
|
+
if (this.certificatePath) {
|
|
3301
|
+
try {
|
|
3302
|
+
const parts = await parseCertificate({ certificatePath: this.certificatePath }, this.sendCertificateChain);
|
|
3303
|
+
this.msalConfig.auth.clientCertificate = {
|
|
3304
|
+
thumbprint: parts.thumbprint,
|
|
3305
|
+
privateKey: parts.certificateContents,
|
|
3306
|
+
x5c: parts.x5c
|
|
3307
|
+
};
|
|
2955
3308
|
}
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
if (!token) {
|
|
2960
|
-
throw new CredentialUnavailableError("Failed to retrieve a valid token");
|
|
3309
|
+
catch (error) {
|
|
3310
|
+
this.logger.info(formatError("", error));
|
|
3311
|
+
throw error;
|
|
2961
3312
|
}
|
|
2962
|
-
return token;
|
|
2963
3313
|
}
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
3314
|
+
else {
|
|
3315
|
+
this.msalConfig.auth.clientSecret = this.clientSecret;
|
|
3316
|
+
}
|
|
3317
|
+
return super.init(options);
|
|
3318
|
+
}
|
|
3319
|
+
async doGetToken(scopes, options = {}) {
|
|
3320
|
+
try {
|
|
3321
|
+
const result = await this.confidentialApp.acquireTokenOnBehalfOf({
|
|
3322
|
+
scopes,
|
|
3323
|
+
correlationId: options.correlationId,
|
|
3324
|
+
authority: options.authority,
|
|
3325
|
+
oboAssertion: this.userAssertionToken
|
|
2968
3326
|
});
|
|
2969
|
-
|
|
2970
|
-
throw err;
|
|
3327
|
+
return this.handleResult(scopes, this.clientId, result || undefined);
|
|
2971
3328
|
}
|
|
2972
|
-
|
|
2973
|
-
|
|
3329
|
+
catch (err) {
|
|
3330
|
+
throw this.handleError(scopes, err, options);
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3334
|
+
|
|
3335
|
+
// Copyright (c) Microsoft Corporation.
|
|
3336
|
+
const credentialName$1 = "OnBehalfOfCredential";
|
|
3337
|
+
const logger$j = credentialLogger(credentialName$1);
|
|
3338
|
+
/**
|
|
3339
|
+
* Enables authentication to Azure Active Directory using the [On Behalf Of flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow).
|
|
3340
|
+
*/
|
|
3341
|
+
class OnBehalfOfCredential {
|
|
3342
|
+
/**
|
|
3343
|
+
* Creates an instance of the {@link OnBehalfOfCredential} with the details
|
|
3344
|
+
* needed to authenticate against Azure Active Directory with a client
|
|
3345
|
+
* secret or a path to a PEM certificate, and an user assertion.
|
|
3346
|
+
*
|
|
3347
|
+
* Example using the `KeyClient` from [\@azure/keyvault-keys](https://www.npmjs.com/package/\@azure/keyvault-keys):
|
|
3348
|
+
*
|
|
3349
|
+
* ```ts
|
|
3350
|
+
* const tokenCredential = new OnBehalfOfCredential({
|
|
3351
|
+
* tenantId,
|
|
3352
|
+
* clientId,
|
|
3353
|
+
* clientSecret, // or `certificatePath: "/path/to/certificate.pem"
|
|
3354
|
+
* userAssertionToken: "access-token"
|
|
3355
|
+
* });
|
|
3356
|
+
* const client = new KeyClient("vault-url", tokenCredential);
|
|
3357
|
+
*
|
|
3358
|
+
* await client.getKey("key-name");
|
|
3359
|
+
* ```
|
|
3360
|
+
*
|
|
3361
|
+
* @param options - Optional parameters, generally common across credentials.
|
|
3362
|
+
*/
|
|
3363
|
+
constructor(options) {
|
|
3364
|
+
this.options = options;
|
|
3365
|
+
const { clientSecret } = options;
|
|
3366
|
+
const { certificatePath } = options;
|
|
3367
|
+
const { tenantId, clientId, userAssertionToken } = options;
|
|
3368
|
+
if (!tenantId || !clientId || !(clientSecret || certificatePath) || !userAssertionToken) {
|
|
3369
|
+
throw new Error(`${credentialName$1}: tenantId, clientId, clientSecret (or certificatePath) and userAssertionToken are required parameters.`);
|
|
2974
3370
|
}
|
|
3371
|
+
this.msalFlow = new MsalOnBehalfOf(Object.assign(Object.assign({}, this.options), { logger: logger$j, tokenCredentialOptions: this.options }));
|
|
3372
|
+
}
|
|
3373
|
+
/**
|
|
3374
|
+
* Authenticates with Azure Active Directory and returns an access token if successful.
|
|
3375
|
+
* If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
|
|
3376
|
+
*
|
|
3377
|
+
* @param scopes - The list of scopes for which the token will have access.
|
|
3378
|
+
* @param options - The options used to configure the underlying network requests.
|
|
3379
|
+
*/
|
|
3380
|
+
async getToken(scopes, options = {}) {
|
|
3381
|
+
return trace(`${credentialName$1}.getToken`, options, async (newOptions) => {
|
|
3382
|
+
const arrayScopes = Array.isArray(scopes) ? scopes : [scopes];
|
|
3383
|
+
return this.msalFlow.getToken(arrayScopes, newOptions);
|
|
3384
|
+
});
|
|
2975
3385
|
}
|
|
2976
3386
|
}
|
|
2977
3387
|
|
|
@@ -3001,11 +3411,12 @@ exports.DeviceCodeCredential = DeviceCodeCredential;
|
|
|
3001
3411
|
exports.EnvironmentCredential = EnvironmentCredential;
|
|
3002
3412
|
exports.InteractiveBrowserCredential = InteractiveBrowserCredential;
|
|
3003
3413
|
exports.ManagedIdentityCredential = ManagedIdentityCredential;
|
|
3414
|
+
exports.OnBehalfOfCredential = OnBehalfOfCredential;
|
|
3004
3415
|
exports.UsernamePasswordCredential = UsernamePasswordCredential;
|
|
3005
3416
|
exports.VisualStudioCodeCredential = VisualStudioCodeCredential;
|
|
3006
3417
|
exports.deserializeAuthenticationRecord = deserializeAuthenticationRecord;
|
|
3007
3418
|
exports.getDefaultAzureCredential = getDefaultAzureCredential;
|
|
3008
3419
|
exports.logger = logger;
|
|
3009
3420
|
exports.serializeAuthenticationRecord = serializeAuthenticationRecord;
|
|
3010
|
-
exports.
|
|
3421
|
+
exports.useIdentityPlugin = useIdentityPlugin;
|
|
3011
3422
|
//# sourceMappingURL=index.js.map
|