@azure/identity 2.0.0-beta.5 → 2.0.1
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 +189 -12
- package/README.md +77 -24
- package/dist/index.js +705 -386
- package/dist/index.js.map +1 -1
- package/dist-esm/src/client/identityClient.js +3 -7
- 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 -76
- package/dist-esm/src/credentials/authorizationCodeCredential.js.map +1 -1
- package/dist-esm/src/credentials/{applicationCredential.browser.js → azureApplicationCredential.browser.js} +9 -4
- 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 +6 -5
- 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 +2 -5
- 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.js +21 -20
- 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/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 +21 -10
- package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js +24 -13
- package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js +22 -11
- package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js +24 -7
- package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js +57 -39
- package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/index.js +16 -14
- 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 +14 -6
- 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 +11 -14
- 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 -5
- 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 +1 -1
- package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/nodeCommon.js +19 -8
- 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 +7 -4
- 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 +1 -1
- 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 +16 -16
- package/types/identity.d.ts +246 -261
- package/dist-esm/src/client/errors.js.map +0 -1
- package/dist-esm/src/credentials/applicationCredential.browser.js.map +0 -1
- package/dist-esm/src/credentials/applicationCredential.js +0 -37
- package/dist-esm/src/credentials/applicationCredential.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
|
@@ -10,7 +10,7 @@ var coreTracing = require('@azure/core-tracing');
|
|
|
10
10
|
var coreUtil = require('@azure/core-util');
|
|
11
11
|
var coreRestPipeline = require('@azure/core-rest-pipeline');
|
|
12
12
|
var abortController = require('@azure/abort-controller');
|
|
13
|
-
var logger$
|
|
13
|
+
var logger$k = require('@azure/logger');
|
|
14
14
|
var msalCommon = require('@azure/msal-common');
|
|
15
15
|
var uuid = require('uuid');
|
|
16
16
|
var fs = require('fs');
|
|
@@ -18,8 +18,10 @@ var fs__default = _interopDefault(fs);
|
|
|
18
18
|
var os = _interopDefault(require('os'));
|
|
19
19
|
var path = _interopDefault(require('path'));
|
|
20
20
|
var child_process = require('child_process');
|
|
21
|
+
var child_process__default = _interopDefault(child_process);
|
|
21
22
|
var crypto = require('crypto');
|
|
22
|
-
var
|
|
23
|
+
var util = require('util');
|
|
24
|
+
var https = _interopDefault(require('https'));
|
|
23
25
|
var http = _interopDefault(require('http'));
|
|
24
26
|
var open = _interopDefault(require('open'));
|
|
25
27
|
var stoppable = _interopDefault(require('stoppable'));
|
|
@@ -149,7 +151,7 @@ const AggregateAuthenticationErrorName = "AggregateAuthenticationError";
|
|
|
149
151
|
class AggregateAuthenticationError extends Error {
|
|
150
152
|
constructor(errors, errorMessage) {
|
|
151
153
|
const errorDetail = errors.join("\n");
|
|
152
|
-
super(`${errorMessage}\n
|
|
154
|
+
super(`${errorMessage}\n${errorDetail}`);
|
|
153
155
|
this.errors = errors;
|
|
154
156
|
// Ensure that this type reports the correct name
|
|
155
157
|
this.name = AggregateAuthenticationErrorName;
|
|
@@ -165,6 +167,21 @@ function convertOAuthErrorResponseToErrorResponse(errorBody) {
|
|
|
165
167
|
traceId: errorBody.trace_id
|
|
166
168
|
};
|
|
167
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
|
+
}
|
|
168
185
|
|
|
169
186
|
// Copyright (c) Microsoft Corporation.
|
|
170
187
|
// Licensed under the MIT license.
|
|
@@ -183,7 +200,7 @@ function getIdentityTokenEndpointSuffix(tenantId) {
|
|
|
183
200
|
* @internal
|
|
184
201
|
*/
|
|
185
202
|
const createSpan = coreTracing.createSpanFunction({
|
|
186
|
-
packagePrefix: "
|
|
203
|
+
packagePrefix: "",
|
|
187
204
|
namespace: "Microsoft.AAD"
|
|
188
205
|
});
|
|
189
206
|
/**
|
|
@@ -224,7 +241,7 @@ async function trace(operationName, options, fn, createSpanFn = createSpan) {
|
|
|
224
241
|
/**
|
|
225
242
|
* The AzureLogger used for all clients within the identity package
|
|
226
243
|
*/
|
|
227
|
-
const logger = logger$
|
|
244
|
+
const logger = logger$k.createClientLogger("identity");
|
|
228
245
|
/**
|
|
229
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.
|
|
230
247
|
* @param supportedEnvVars - List of environment variable names
|
|
@@ -315,7 +332,7 @@ function getIdentityClientAuthorityHost(options) {
|
|
|
315
332
|
class IdentityClient extends coreClient.ServiceClient {
|
|
316
333
|
constructor(options) {
|
|
317
334
|
var _a;
|
|
318
|
-
const packageDetails = `azsdk-js-identity/2.0.
|
|
335
|
+
const packageDetails = `azsdk-js-identity/2.0.1`;
|
|
319
336
|
const userAgentPrefix = ((_a = options === null || options === void 0 ? void 0 : options.userAgentOptions) === null || _a === void 0 ? void 0 : _a.userAgentPrefix)
|
|
320
337
|
? `${options.userAgentOptions.userAgentPrefix} ${packageDetails}`
|
|
321
338
|
: `${packageDetails}`;
|
|
@@ -359,7 +376,6 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
|
359
376
|
}
|
|
360
377
|
}
|
|
361
378
|
async refreshAccessToken(tenantId, clientId, scopes, refreshToken, clientSecret, expiresOnParser, options) {
|
|
362
|
-
var _a, _b;
|
|
363
379
|
if (refreshToken === undefined) {
|
|
364
380
|
return null;
|
|
365
381
|
}
|
|
@@ -386,10 +402,7 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
|
386
402
|
Accept: "application/json",
|
|
387
403
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
388
404
|
}),
|
|
389
|
-
tracingOptions:
|
|
390
|
-
spanOptions: (_a = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _a === void 0 ? void 0 : _a.spanOptions,
|
|
391
|
-
tracingContext: (_b = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _b === void 0 ? void 0 : _b.tracingContext
|
|
392
|
-
}
|
|
405
|
+
tracingOptions: updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions
|
|
393
406
|
});
|
|
394
407
|
const response = await this.sendTokenRequest(request, expiresOnParser);
|
|
395
408
|
logger.info(`IdentityClient: refreshed token for client ID: ${clientId}`);
|
|
@@ -515,28 +528,6 @@ function resolveTenantId(logger, tenantId, clientId) {
|
|
|
515
528
|
return "organizations";
|
|
516
529
|
}
|
|
517
530
|
|
|
518
|
-
// Copyright (c) Microsoft Corporation.
|
|
519
|
-
// Licensed under the MIT license.
|
|
520
|
-
/**
|
|
521
|
-
* Error used to enforce authentication after trying to retrieve a token silently.
|
|
522
|
-
*/
|
|
523
|
-
class AuthenticationRequiredError extends Error {
|
|
524
|
-
constructor(
|
|
525
|
-
/**
|
|
526
|
-
* The list of scopes for which the token will have access.
|
|
527
|
-
*/
|
|
528
|
-
scopes,
|
|
529
|
-
/**
|
|
530
|
-
* The options used to configure the getToken request.
|
|
531
|
-
*/
|
|
532
|
-
getTokenOptions = {}, message) {
|
|
533
|
-
super(message);
|
|
534
|
-
this.scopes = scopes;
|
|
535
|
-
this.getTokenOptions = getTokenOptions;
|
|
536
|
-
this.name = "AuthenticationRequiredError";
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
|
|
540
531
|
// Copyright (c) Microsoft Corporation.
|
|
541
532
|
/**
|
|
542
533
|
* Latest AuthenticationRecord version
|
|
@@ -550,7 +541,11 @@ const LatestAuthenticationRecordVersion = "1.0";
|
|
|
550
541
|
function ensureValidMsalToken(scopes, logger, msalToken, getTokenOptions) {
|
|
551
542
|
const error = (message) => {
|
|
552
543
|
logger.getToken.info(message);
|
|
553
|
-
return new AuthenticationRequiredError(
|
|
544
|
+
return new AuthenticationRequiredError({
|
|
545
|
+
scopes: Array.isArray(scopes) ? scopes : [scopes],
|
|
546
|
+
getTokenOptions,
|
|
547
|
+
message
|
|
548
|
+
});
|
|
554
549
|
};
|
|
555
550
|
if (!msalToken) {
|
|
556
551
|
throw error("No response");
|
|
@@ -678,7 +673,7 @@ class MsalBaseUtilities {
|
|
|
678
673
|
error.name === "AbortError") {
|
|
679
674
|
return error;
|
|
680
675
|
}
|
|
681
|
-
return new AuthenticationRequiredError(scopes, getTokenOptions, error.message);
|
|
676
|
+
return new AuthenticationRequiredError({ scopes, getTokenOptions, message: error.message });
|
|
682
677
|
}
|
|
683
678
|
}
|
|
684
679
|
// transformations.ts
|
|
@@ -742,6 +737,40 @@ function deserializeAuthenticationRecord(serializedRecord) {
|
|
|
742
737
|
}
|
|
743
738
|
|
|
744
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;
|
|
745
774
|
(function (RegionalAuthority) {
|
|
746
775
|
/** Instructs MSAL to attempt to discover the region */
|
|
747
776
|
RegionalAuthority["AutoDiscoverRegion"] = "AutoDiscoverRegion";
|
|
@@ -849,31 +878,7 @@ function deserializeAuthenticationRecord(serializedRecord) {
|
|
|
849
878
|
RegionalAuthority["GovernmentUSDodEast"] = "usdodeast";
|
|
850
879
|
/** Uses the {@link RegionalAuthority} for the Azure 'usdodcentral' region. */
|
|
851
880
|
RegionalAuthority["GovernmentUSDodCentral"] = "usdodcentral";
|
|
852
|
-
})(
|
|
853
|
-
|
|
854
|
-
// Copyright (c) Microsoft Corporation.
|
|
855
|
-
// Licensed under the MIT license.
|
|
856
|
-
/**
|
|
857
|
-
* @internal
|
|
858
|
-
*/
|
|
859
|
-
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.";
|
|
860
|
-
/**
|
|
861
|
-
* Verifies whether locally assigned tenants are equal to tenants received through getToken.
|
|
862
|
-
* Returns the appropriate tenant.
|
|
863
|
-
* @internal
|
|
864
|
-
*/
|
|
865
|
-
function processMultiTenantRequest(tenantId, allowMultiTenantAuthentication, getTokenOptions) {
|
|
866
|
-
if (!allowMultiTenantAuthentication &&
|
|
867
|
-
(getTokenOptions === null || getTokenOptions === void 0 ? void 0 : getTokenOptions.tenantId) &&
|
|
868
|
-
tenantId &&
|
|
869
|
-
getTokenOptions.tenantId !== tenantId) {
|
|
870
|
-
throw new Error(multiTenantErrorMessage);
|
|
871
|
-
}
|
|
872
|
-
if (allowMultiTenantAuthentication && (getTokenOptions === null || getTokenOptions === void 0 ? void 0 : getTokenOptions.tenantId)) {
|
|
873
|
-
return getTokenOptions.tenantId;
|
|
874
|
-
}
|
|
875
|
-
return tenantId;
|
|
876
|
-
}
|
|
881
|
+
})(RegionalAuthority || (RegionalAuthority = {}));
|
|
877
882
|
|
|
878
883
|
// Copyright (c) Microsoft Corporation.
|
|
879
884
|
/**
|
|
@@ -906,17 +911,21 @@ class MsalNode extends MsalBaseUtilities {
|
|
|
906
911
|
this.requiresConfidential = false;
|
|
907
912
|
this.msalConfig = this.defaultNodeMsalConfig(options);
|
|
908
913
|
this.tenantId = resolveTenantId(options.logger, options.tenantId, options.clientId);
|
|
909
|
-
this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
|
|
910
914
|
this.clientId = this.msalConfig.auth.clientId;
|
|
911
915
|
// If persistence has been configured
|
|
912
916
|
if (persistenceProvider !== undefined && ((_a = options.tokenCachePersistenceOptions) === null || _a === void 0 ? void 0 : _a.enabled)) {
|
|
913
917
|
this.createCachePlugin = () => persistenceProvider(options.tokenCachePersistenceOptions);
|
|
914
918
|
}
|
|
915
919
|
else if ((_b = options.tokenCachePersistenceOptions) === null || _b === void 0 ? void 0 : _b.enabled) {
|
|
916
|
-
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(" "));
|
|
917
926
|
}
|
|
918
927
|
this.azureRegion = (_c = options.regionalAuthority) !== null && _c !== void 0 ? _c : process.env.AZURE_REGIONAL_AUTHORITY_NAME;
|
|
919
|
-
if (this.azureRegion ===
|
|
928
|
+
if (this.azureRegion === RegionalAuthority.AutoDiscoverRegion) {
|
|
920
929
|
this.azureRegion = "AUTO_DISCOVER";
|
|
921
930
|
}
|
|
922
931
|
}
|
|
@@ -1032,7 +1041,11 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
|
|
|
1032
1041
|
var _a, _b;
|
|
1033
1042
|
await this.getActiveAccount();
|
|
1034
1043
|
if (!this.account) {
|
|
1035
|
-
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
|
+
});
|
|
1036
1049
|
}
|
|
1037
1050
|
const silentRequest = {
|
|
1038
1051
|
// To be able to re-use the account, the Token Cache must also have been provided.
|
|
@@ -1055,8 +1068,7 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
|
|
|
1055
1068
|
* If disableAutomaticAuthentication is sent through the constructor, it will prevent MSAL from requesting the user input.
|
|
1056
1069
|
*/
|
|
1057
1070
|
async getToken(scopes, options = {}) {
|
|
1058
|
-
const tenantId = processMultiTenantRequest(this.tenantId,
|
|
1059
|
-
this.tenantId;
|
|
1071
|
+
const tenantId = processMultiTenantRequest(this.tenantId, options) || this.tenantId;
|
|
1060
1072
|
options.authority = getAuthority(tenantId, this.authorityHost);
|
|
1061
1073
|
options.correlationId = (options === null || options === void 0 ? void 0 : options.correlationId) || this.generateUuid();
|
|
1062
1074
|
await this.init(options);
|
|
@@ -1068,7 +1080,11 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
|
|
|
1068
1080
|
throw err;
|
|
1069
1081
|
}
|
|
1070
1082
|
if (options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication) {
|
|
1071
|
-
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
|
+
});
|
|
1072
1088
|
}
|
|
1073
1089
|
this.logger.info(`Silent authentication failed, falling back to interactive method.`);
|
|
1074
1090
|
return this.doGetToken(scopes, options);
|
|
@@ -1137,7 +1153,7 @@ function getPropertyFromVSCode(property) {
|
|
|
1137
1153
|
}
|
|
1138
1154
|
}
|
|
1139
1155
|
/**
|
|
1140
|
-
*
|
|
1156
|
+
* Connects to Azure using the credential provided by the VSCode extension 'Azure Account'.
|
|
1141
1157
|
* Once the user has logged in via the extension, this credential can share the same refresh token
|
|
1142
1158
|
* that is cached by the extension.
|
|
1143
1159
|
*/
|
|
@@ -1145,6 +1161,11 @@ class VisualStudioCodeCredential {
|
|
|
1145
1161
|
/**
|
|
1146
1162
|
* Creates an instance of VisualStudioCodeCredential to use for automatically authenticating via VSCode.
|
|
1147
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
|
+
*
|
|
1148
1169
|
* @param options - Options for configuring the client which makes the authentication request.
|
|
1149
1170
|
*/
|
|
1150
1171
|
constructor(options) {
|
|
@@ -1161,7 +1182,6 @@ class VisualStudioCodeCredential {
|
|
|
1161
1182
|
else {
|
|
1162
1183
|
this.tenantId = CommonTenantId;
|
|
1163
1184
|
}
|
|
1164
|
-
this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
|
|
1165
1185
|
checkUnsupportedTenant(this.tenantId);
|
|
1166
1186
|
}
|
|
1167
1187
|
/**
|
|
@@ -1195,10 +1215,14 @@ class VisualStudioCodeCredential {
|
|
|
1195
1215
|
async getToken(scopes, options) {
|
|
1196
1216
|
var _a, _b;
|
|
1197
1217
|
await this.prepareOnce();
|
|
1198
|
-
const tenantId = processMultiTenantRequest(this.tenantId,
|
|
1199
|
-
this.tenantId;
|
|
1218
|
+
const tenantId = processMultiTenantRequest(this.tenantId, options) || this.tenantId;
|
|
1200
1219
|
if (findCredentials === undefined) {
|
|
1201
|
-
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(" "));
|
|
1202
1226
|
}
|
|
1203
1227
|
let scopeString = typeof scopes === "string" ? scopes : scopes.join(" ");
|
|
1204
1228
|
// Check to make sure the scope we get back is a valid scope
|
|
@@ -1228,13 +1252,13 @@ class VisualStudioCodeCredential {
|
|
|
1228
1252
|
return tokenResponse.accessToken;
|
|
1229
1253
|
}
|
|
1230
1254
|
else {
|
|
1231
|
-
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.");
|
|
1232
1256
|
logger$1.getToken.info(formatError(scopes, error));
|
|
1233
1257
|
throw error;
|
|
1234
1258
|
}
|
|
1235
1259
|
}
|
|
1236
1260
|
else {
|
|
1237
|
-
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.");
|
|
1238
1262
|
logger$1.getToken.info(formatError(scopes, error));
|
|
1239
1263
|
throw error;
|
|
1240
1264
|
}
|
|
@@ -1243,17 +1267,17 @@ class VisualStudioCodeCredential {
|
|
|
1243
1267
|
|
|
1244
1268
|
// Copyright (c) Microsoft Corporation.
|
|
1245
1269
|
/**
|
|
1246
|
-
* The context passed to an Identity
|
|
1247
|
-
*
|
|
1270
|
+
* The context passed to an Identity plugin. This contains objects that
|
|
1271
|
+
* plugins can use to set backend implementations.
|
|
1248
1272
|
* @internal
|
|
1249
1273
|
*/
|
|
1250
|
-
const
|
|
1274
|
+
const pluginContext = {
|
|
1251
1275
|
cachePluginControl: msalNodeFlowCacheControl,
|
|
1252
1276
|
vsCodeCredentialControl: vsCodeCredentialControl
|
|
1253
1277
|
};
|
|
1254
1278
|
/**
|
|
1255
|
-
* Extend Azure Identity with additional functionality. Pass
|
|
1256
|
-
*
|
|
1279
|
+
* Extend Azure Identity with additional functionality. Pass a plugin from
|
|
1280
|
+
* a plugin package, such as:
|
|
1257
1281
|
*
|
|
1258
1282
|
* - `@azure/identity-cache-persistence`: provides persistent token caching
|
|
1259
1283
|
* - `@azure/identity-vscode`: provides the dependencies of
|
|
@@ -1262,12 +1286,12 @@ const extensionContext = {
|
|
|
1262
1286
|
* Example:
|
|
1263
1287
|
*
|
|
1264
1288
|
* ```javascript
|
|
1265
|
-
* import {
|
|
1289
|
+
* import { cachePersistencePlugin } from "@azure/identity-cache-persistence";
|
|
1266
1290
|
*
|
|
1267
|
-
* import {
|
|
1268
|
-
*
|
|
1291
|
+
* import { useIdentityPlugin, DefaultAzureCredential } from "@azure/identity";
|
|
1292
|
+
* useIdentityPlugin(cachePersistencePlugin);
|
|
1269
1293
|
*
|
|
1270
|
-
* // The
|
|
1294
|
+
* // The plugin has the capability to extend `DefaultAzureCredential` and to
|
|
1271
1295
|
* // add middleware to the underlying credentials, such as persistence.
|
|
1272
1296
|
* const credential = new DefaultAzureCredential({
|
|
1273
1297
|
* tokenCachePersistenceOptions: {
|
|
@@ -1276,10 +1300,10 @@ const extensionContext = {
|
|
|
1276
1300
|
* });
|
|
1277
1301
|
* ```
|
|
1278
1302
|
*
|
|
1279
|
-
* @param
|
|
1303
|
+
* @param plugin - the plugin to register
|
|
1280
1304
|
*/
|
|
1281
|
-
function
|
|
1282
|
-
|
|
1305
|
+
function useIdentityPlugin(plugin) {
|
|
1306
|
+
plugin(pluginContext);
|
|
1283
1307
|
}
|
|
1284
1308
|
|
|
1285
1309
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -1327,12 +1351,13 @@ class ChainedTokenCredential {
|
|
|
1327
1351
|
*/
|
|
1328
1352
|
async getToken(scopes, options) {
|
|
1329
1353
|
let token = null;
|
|
1354
|
+
let successfulCredentialName = "";
|
|
1330
1355
|
const errors = [];
|
|
1331
|
-
const { span, updatedOptions } = createSpan("ChainedTokenCredential
|
|
1356
|
+
const { span, updatedOptions } = createSpan("ChainedTokenCredential.getToken", options);
|
|
1332
1357
|
for (let i = 0; i < this._sources.length && token === null; i++) {
|
|
1333
1358
|
try {
|
|
1334
1359
|
token = await this._sources[i].getToken(scopes, updatedOptions);
|
|
1335
|
-
|
|
1360
|
+
successfulCredentialName = this._sources[i].constructor.name;
|
|
1336
1361
|
}
|
|
1337
1362
|
catch (err) {
|
|
1338
1363
|
if (err.name === "CredentialUnavailableError" ||
|
|
@@ -1346,7 +1371,7 @@ class ChainedTokenCredential {
|
|
|
1346
1371
|
}
|
|
1347
1372
|
}
|
|
1348
1373
|
if (!token && errors.length > 0) {
|
|
1349
|
-
const err = new AggregateAuthenticationError(errors);
|
|
1374
|
+
const err = new AggregateAuthenticationError(errors, "ChainedTokenCredential authentication failed.");
|
|
1350
1375
|
span.setStatus({
|
|
1351
1376
|
code: coreTracing.SpanStatusCode.ERROR,
|
|
1352
1377
|
message: err.message
|
|
@@ -1355,7 +1380,7 @@ class ChainedTokenCredential {
|
|
|
1355
1380
|
throw err;
|
|
1356
1381
|
}
|
|
1357
1382
|
span.end();
|
|
1358
|
-
logger$2.getToken.info(`Result for ${
|
|
1383
|
+
logger$2.getToken.info(`Result for ${successfulCredentialName}: ${formatSuccess(scopes)}`);
|
|
1359
1384
|
if (token === null) {
|
|
1360
1385
|
throw new CredentialUnavailableError("Failed to retrieve a valid token");
|
|
1361
1386
|
}
|
|
@@ -1415,15 +1440,15 @@ const cliCredentialInternals = {
|
|
|
1415
1440
|
}
|
|
1416
1441
|
return new Promise((resolve, reject) => {
|
|
1417
1442
|
try {
|
|
1418
|
-
|
|
1443
|
+
child_process__default.execFile("az", [
|
|
1419
1444
|
"account",
|
|
1420
1445
|
"get-access-token",
|
|
1421
1446
|
"--output",
|
|
1422
1447
|
"json",
|
|
1423
1448
|
"--resource",
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
], { cwd: cliCredentialInternals.getSafeWorkingDir() }, (error, stdout, stderr) => {
|
|
1449
|
+
resource,
|
|
1450
|
+
...tenantSection
|
|
1451
|
+
], { cwd: cliCredentialInternals.getSafeWorkingDir(), shell: true }, (error, stdout, stderr) => {
|
|
1427
1452
|
resolve({ stdout: stdout, stderr: stderr, error });
|
|
1428
1453
|
});
|
|
1429
1454
|
}
|
|
@@ -1439,18 +1464,18 @@ const logger$3 = credentialLogger("AzureCliCredential");
|
|
|
1439
1464
|
* via the Azure CLI ('az') commandline tool.
|
|
1440
1465
|
* To do so, it will read the user access token and expire time
|
|
1441
1466
|
* with Azure CLI command "az account get-access-token".
|
|
1442
|
-
* To be able to use this credential, ensure that you have already logged
|
|
1443
|
-
* in via the 'az' tool using the command "az login" from the commandline.
|
|
1444
1467
|
*/
|
|
1445
1468
|
class AzureCliCredential {
|
|
1446
1469
|
/**
|
|
1447
1470
|
* Creates an instance of the {@link AzureCliCredential}.
|
|
1448
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
|
+
*
|
|
1449
1475
|
* @param options - Options, to optionally allow multi-tenant requests.
|
|
1450
1476
|
*/
|
|
1451
1477
|
constructor(options) {
|
|
1452
1478
|
this.tenantId = options === null || options === void 0 ? void 0 : options.tenantId;
|
|
1453
|
-
this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
|
|
1454
1479
|
}
|
|
1455
1480
|
/**
|
|
1456
1481
|
* Authenticates with Azure Active Directory and returns an access token if successful.
|
|
@@ -1461,7 +1486,7 @@ class AzureCliCredential {
|
|
|
1461
1486
|
* TokenCredential implementation might make.
|
|
1462
1487
|
*/
|
|
1463
1488
|
async getToken(scopes, options) {
|
|
1464
|
-
const tenantId = processMultiTenantRequest(this.tenantId,
|
|
1489
|
+
const tenantId = processMultiTenantRequest(this.tenantId, options);
|
|
1465
1490
|
if (tenantId) {
|
|
1466
1491
|
checkTenantId(logger$3, tenantId);
|
|
1467
1492
|
}
|
|
@@ -1470,7 +1495,7 @@ class AzureCliCredential {
|
|
|
1470
1495
|
ensureValidScope(scope, logger$3);
|
|
1471
1496
|
const resource = getScopeResource(scope);
|
|
1472
1497
|
let responseData = "";
|
|
1473
|
-
const { span } = createSpan("AzureCliCredential
|
|
1498
|
+
const { span } = createSpan("AzureCliCredential.getToken", options);
|
|
1474
1499
|
try {
|
|
1475
1500
|
const obj = await cliCredentialInternals.getAzureCliAccessToken(resource, tenantId);
|
|
1476
1501
|
if (obj.stderr) {
|
|
@@ -1587,7 +1612,8 @@ const powerShellErrors = {
|
|
|
1587
1612
|
*/
|
|
1588
1613
|
const powerShellPublicErrorMessages = {
|
|
1589
1614
|
login: "Please run 'Connect-AzAccount' from PowerShell to authenticate before using this credential.",
|
|
1590
|
-
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.`
|
|
1591
1617
|
};
|
|
1592
1618
|
// PowerShell Azure User not logged in error check.
|
|
1593
1619
|
const isLoginError = (err) => err.message.match(`(.*)${powerShellErrors.login}(.*)`);
|
|
@@ -1606,22 +1632,21 @@ if (isWindows) {
|
|
|
1606
1632
|
* This credential will use the currently logged-in user information from the
|
|
1607
1633
|
* Azure PowerShell module. To do so, it will read the user access token and
|
|
1608
1634
|
* expire time with Azure PowerShell command `Get-AzAccessToken -ResourceUrl {ResourceScope}`
|
|
1609
|
-
*
|
|
1610
|
-
* To be able to use this credential:
|
|
1611
|
-
* - Install the Azure Az PowerShell module with:
|
|
1612
|
-
* `Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force`.
|
|
1613
|
-
* - You have already logged in to Azure PowerShell using the command
|
|
1614
|
-
* `Connect-AzAccount` from the command line.
|
|
1615
1635
|
*/
|
|
1616
1636
|
class AzurePowerShellCredential {
|
|
1617
1637
|
/**
|
|
1618
|
-
* 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.
|
|
1619
1645
|
*
|
|
1620
1646
|
* @param options - Options, to optionally allow multi-tenant requests.
|
|
1621
1647
|
*/
|
|
1622
1648
|
constructor(options) {
|
|
1623
1649
|
this.tenantId = options === null || options === void 0 ? void 0 : options.tenantId;
|
|
1624
|
-
this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
|
|
1625
1650
|
}
|
|
1626
1651
|
/**
|
|
1627
1652
|
* Gets the access token from Azure PowerShell
|
|
@@ -1662,7 +1687,7 @@ class AzurePowerShellCredential {
|
|
|
1662
1687
|
throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);
|
|
1663
1688
|
}
|
|
1664
1689
|
}
|
|
1665
|
-
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`);
|
|
1666
1691
|
}
|
|
1667
1692
|
/**
|
|
1668
1693
|
* Authenticates with Azure Active Directory and returns an access token if successful.
|
|
@@ -1673,7 +1698,7 @@ class AzurePowerShellCredential {
|
|
|
1673
1698
|
*/
|
|
1674
1699
|
async getToken(scopes, options = {}) {
|
|
1675
1700
|
return trace(`${this.constructor.name}.getToken`, options, async () => {
|
|
1676
|
-
const tenantId = processMultiTenantRequest(this.tenantId,
|
|
1701
|
+
const tenantId = processMultiTenantRequest(this.tenantId, options);
|
|
1677
1702
|
if (tenantId) {
|
|
1678
1703
|
checkTenantId(logger$4, tenantId);
|
|
1679
1704
|
}
|
|
@@ -1700,7 +1725,7 @@ class AzurePowerShellCredential {
|
|
|
1700
1725
|
logger$4.getToken.info(formatError(scope, error));
|
|
1701
1726
|
throw error;
|
|
1702
1727
|
}
|
|
1703
|
-
const error = new CredentialUnavailableError(err);
|
|
1728
|
+
const error = new CredentialUnavailableError(`${err}. ${powerShellPublicErrorMessages.troubleshoot}`);
|
|
1704
1729
|
logger$4.getToken.info(formatError(scope, error));
|
|
1705
1730
|
throw error;
|
|
1706
1731
|
}
|
|
@@ -1759,6 +1784,9 @@ class ClientSecretCredential {
|
|
|
1759
1784
|
* @param options - Options for configuring the client which makes the authentication request.
|
|
1760
1785
|
*/
|
|
1761
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
|
+
}
|
|
1762
1790
|
this.msalFlow = new MsalClientSecret(Object.assign(Object.assign({}, options), { logger: logger$5,
|
|
1763
1791
|
clientId,
|
|
1764
1792
|
tenantId,
|
|
@@ -1781,6 +1809,41 @@ class ClientSecretCredential {
|
|
|
1781
1809
|
}
|
|
1782
1810
|
|
|
1783
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
|
+
}
|
|
1784
1847
|
/**
|
|
1785
1848
|
* MSAL client certificate client. Calls to MSAL's confidential application's `acquireTokenByClientCredential` during `doGetToken`.
|
|
1786
1849
|
* @internal
|
|
@@ -1789,40 +1852,24 @@ class MsalClientCertificate extends MsalNode {
|
|
|
1789
1852
|
constructor(options) {
|
|
1790
1853
|
super(options);
|
|
1791
1854
|
this.requiresConfidential = true;
|
|
1855
|
+
this.configuration = options.configuration;
|
|
1792
1856
|
this.sendCertificateChain = options.sendCertificateChain;
|
|
1793
|
-
const parts = this.parseCertificate(options.certificatePath);
|
|
1794
|
-
this.msalConfig.auth.clientCertificate = {
|
|
1795
|
-
thumbprint: parts.thumbprint,
|
|
1796
|
-
privateKey: parts.certificateContents,
|
|
1797
|
-
x5c: parts.x5c
|
|
1798
|
-
};
|
|
1799
1857
|
}
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
match = certificatePattern.exec(certificateParts.certificateContents);
|
|
1812
|
-
if (match) {
|
|
1813
|
-
publicKeys.push(match[3]);
|
|
1814
|
-
}
|
|
1815
|
-
} while (match);
|
|
1816
|
-
if (publicKeys.length === 0) {
|
|
1817
|
-
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) {
|
|
1818
1869
|
this.logger.info(formatError("", error));
|
|
1819
1870
|
throw error;
|
|
1820
1871
|
}
|
|
1821
|
-
|
|
1822
|
-
.update(Buffer.from(publicKeys[0], "base64"))
|
|
1823
|
-
.digest("hex")
|
|
1824
|
-
.toUpperCase();
|
|
1825
|
-
return certificateParts;
|
|
1872
|
+
return super.init(options);
|
|
1826
1873
|
}
|
|
1827
1874
|
async doGetToken(scopes, options = {}) {
|
|
1828
1875
|
try {
|
|
@@ -1844,7 +1891,8 @@ class MsalClientCertificate extends MsalNode {
|
|
|
1844
1891
|
}
|
|
1845
1892
|
|
|
1846
1893
|
// Copyright (c) Microsoft Corporation.
|
|
1847
|
-
const
|
|
1894
|
+
const credentialName = "ClientCertificateCredential";
|
|
1895
|
+
const logger$6 = credentialLogger(credentialName);
|
|
1848
1896
|
/**
|
|
1849
1897
|
* Enables authentication to Azure Active Directory using a PEM-encoded
|
|
1850
1898
|
* certificate that is assigned to an App Registration. More information
|
|
@@ -1854,17 +1902,22 @@ const logger$6 = credentialLogger("ClientCertificateCredential");
|
|
|
1854
1902
|
*
|
|
1855
1903
|
*/
|
|
1856
1904
|
class ClientCertificateCredential {
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
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,
|
|
1868
1921
|
logger: logger$6,
|
|
1869
1922
|
clientId,
|
|
1870
1923
|
tenantId, sendCertificateChain: options.sendCertificateChain, tokenCredentialOptions: options }));
|
|
@@ -1878,7 +1931,7 @@ class ClientCertificateCredential {
|
|
|
1878
1931
|
* TokenCredential implementation might make.
|
|
1879
1932
|
*/
|
|
1880
1933
|
async getToken(scopes, options = {}) {
|
|
1881
|
-
return trace(`${
|
|
1934
|
+
return trace(`${credentialName}.getToken`, options, async (newOptions) => {
|
|
1882
1935
|
const arrayScopes = Array.isArray(scopes) ? scopes : [scopes];
|
|
1883
1936
|
return this.msalFlow.getToken(arrayScopes, newOptions);
|
|
1884
1937
|
});
|
|
@@ -1922,8 +1975,6 @@ const logger$7 = credentialLogger("UsernamePasswordCredential");
|
|
|
1922
1975
|
* trust so you should only use it when other, more secure credential
|
|
1923
1976
|
* types can't be used.
|
|
1924
1977
|
*/
|
|
1925
|
-
// We'll be using InteractiveCredential as the base of this class, which requires us to support authenticate(),
|
|
1926
|
-
// to reduce the number of times we send the password over the network.
|
|
1927
1978
|
class UsernamePasswordCredential {
|
|
1928
1979
|
/**
|
|
1929
1980
|
* Creates an instance of the UsernamePasswordCredential with the details
|
|
@@ -1937,6 +1988,9 @@ class UsernamePasswordCredential {
|
|
|
1937
1988
|
* @param options - Options for configuring the client which makes the authentication request.
|
|
1938
1989
|
*/
|
|
1939
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
|
+
}
|
|
1940
1994
|
this.msalFlow = new MsalUsernamePassword(Object.assign(Object.assign({}, options), { logger: logger$7,
|
|
1941
1995
|
clientId,
|
|
1942
1996
|
tenantId,
|
|
@@ -1982,23 +2036,7 @@ const AllSupportedEnvironmentVariables = [
|
|
|
1982
2036
|
const logger$8 = credentialLogger("EnvironmentCredential");
|
|
1983
2037
|
/**
|
|
1984
2038
|
* Enables authentication to Azure Active Directory using client secret
|
|
1985
|
-
* details configured in
|
|
1986
|
-
*
|
|
1987
|
-
* Required environment variables:
|
|
1988
|
-
* - `AZURE_TENANT_ID`: The Azure Active Directory tenant (directory) ID.
|
|
1989
|
-
* - `AZURE_CLIENT_ID`: The client (application) ID of an App Registration in the tenant.
|
|
1990
|
-
*
|
|
1991
|
-
* Environment variables used for client credential authentication:
|
|
1992
|
-
* - `AZURE_CLIENT_SECRET`: A client secret that was generated for the App Registration.
|
|
1993
|
-
* - `AZURE_CLIENT_CERTIFICATE_PATH`: The path to a PEM certificate to use during the authentication, instead of the client secret.
|
|
1994
|
-
*
|
|
1995
|
-
* Alternatively, users can provide environment variables for username and password authentication:
|
|
1996
|
-
* - `AZURE_USERNAME`: Username to authenticate with.
|
|
1997
|
-
* - `AZURE_PASSWORD`: Password to authenticate with.
|
|
1998
|
-
*
|
|
1999
|
-
* This credential ultimately uses a {@link ClientSecretCredential} to
|
|
2000
|
-
* perform the authentication using these details. Please consult the
|
|
2001
|
-
* documentation of that class for more details.
|
|
2039
|
+
* details configured in environment variables
|
|
2002
2040
|
*/
|
|
2003
2041
|
class EnvironmentCredential {
|
|
2004
2042
|
/**
|
|
@@ -2038,7 +2076,7 @@ class EnvironmentCredential {
|
|
|
2038
2076
|
const certificatePath = process.env.AZURE_CLIENT_CERTIFICATE_PATH;
|
|
2039
2077
|
if (tenantId && clientId && certificatePath) {
|
|
2040
2078
|
logger$8.info(`Invoking ClientCertificateCredential with tenant ID: ${tenantId}, clientId: ${clientId} and certificatePath: ${certificatePath}`);
|
|
2041
|
-
this._credential = new ClientCertificateCredential(tenantId, clientId, certificatePath, options);
|
|
2079
|
+
this._credential = new ClientCertificateCredential(tenantId, clientId, { certificatePath }, options);
|
|
2042
2080
|
return;
|
|
2043
2081
|
}
|
|
2044
2082
|
const username = process.env.AZURE_USERNAME;
|
|
@@ -2064,7 +2102,7 @@ class EnvironmentCredential {
|
|
|
2064
2102
|
}
|
|
2065
2103
|
catch (err) {
|
|
2066
2104
|
const authenticationError = new AuthenticationError(400, {
|
|
2067
|
-
error: "EnvironmentCredential authentication failed.",
|
|
2105
|
+
error: "EnvironmentCredential authentication failed. To troubleshoot, visit https://aka.ms/azsdk/js/identity/environmentcredential/troubleshoot.",
|
|
2068
2106
|
error_description: err.message
|
|
2069
2107
|
.toString()
|
|
2070
2108
|
.split("More details:")
|
|
@@ -2074,7 +2112,7 @@ class EnvironmentCredential {
|
|
|
2074
2112
|
throw authenticationError;
|
|
2075
2113
|
}
|
|
2076
2114
|
}
|
|
2077
|
-
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.");
|
|
2078
2116
|
});
|
|
2079
2117
|
}
|
|
2080
2118
|
}
|
|
@@ -2086,13 +2124,22 @@ const imdsHost = "http://169.254.169.254";
|
|
|
2086
2124
|
const imdsEndpointPath = "/metadata/identity/oauth2/token";
|
|
2087
2125
|
const imdsApiVersion = "2018-02-01";
|
|
2088
2126
|
const azureArcAPIVersion = "2019-11-01";
|
|
2127
|
+
const azureFabricVersion = "2019-07-01-preview";
|
|
2089
2128
|
|
|
2090
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
|
+
*/
|
|
2091
2138
|
function mapScopesToResource(scopes) {
|
|
2092
2139
|
let scope = "";
|
|
2093
2140
|
if (Array.isArray(scopes)) {
|
|
2094
2141
|
if (scopes.length !== 1) {
|
|
2095
|
-
|
|
2142
|
+
return;
|
|
2096
2143
|
}
|
|
2097
2144
|
scope = scopes[0];
|
|
2098
2145
|
}
|
|
@@ -2104,23 +2151,28 @@ function mapScopesToResource(scopes) {
|
|
|
2104
2151
|
}
|
|
2105
2152
|
return scope.substr(0, scope.lastIndexOf(DefaultScopeSuffix));
|
|
2106
2153
|
}
|
|
2107
|
-
async function msiGenericGetToken(identityClient, requestOptions, expiresInParser, getTokenOptions = {}) {
|
|
2108
|
-
const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal,
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
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
|
+
}
|
|
2112
2159
|
const tokenResponse = await identityClient.sendTokenRequest(request, expiresInParser);
|
|
2113
2160
|
return (tokenResponse && tokenResponse.accessToken) || null;
|
|
2114
2161
|
}
|
|
2115
2162
|
|
|
2116
2163
|
// Copyright (c) Microsoft Corporation.
|
|
2117
|
-
const
|
|
2164
|
+
const msiName = "ManagedIdentityCredential - AppServiceMSI 2017";
|
|
2165
|
+
const logger$9 = credentialLogger(msiName);
|
|
2118
2166
|
function expiresInParser(requestBody) {
|
|
2119
2167
|
// Parse a date format like "06/20/2019 02:57:58 +00:00" and
|
|
2120
2168
|
// convert it into a JavaScript-formatted date
|
|
2121
2169
|
return Date.parse(requestBody.expires_on);
|
|
2122
2170
|
}
|
|
2123
|
-
function prepareRequestOptions(
|
|
2171
|
+
function prepareRequestOptions(scopes, clientId) {
|
|
2172
|
+
const resource = mapScopesToResource(scopes);
|
|
2173
|
+
if (!resource) {
|
|
2174
|
+
throw new Error(`${msiName}: Multiple scopes are not supported.`);
|
|
2175
|
+
}
|
|
2124
2176
|
const queryParameters = {
|
|
2125
2177
|
resource,
|
|
2126
2178
|
"api-version": "2017-09-01"
|
|
@@ -2131,10 +2183,10 @@ function prepareRequestOptions(resource, clientId) {
|
|
|
2131
2183
|
const query = new URLSearchParams(queryParameters);
|
|
2132
2184
|
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
2133
2185
|
if (!process.env.MSI_ENDPOINT) {
|
|
2134
|
-
throw new Error(
|
|
2186
|
+
throw new Error(`${msiName}: Missing environment variable: MSI_ENDPOINT`);
|
|
2135
2187
|
}
|
|
2136
2188
|
if (!process.env.MSI_SECRET) {
|
|
2137
|
-
throw new Error(
|
|
2189
|
+
throw new Error(`${msiName}: Missing environment variable: MSI_SECRET`);
|
|
2138
2190
|
}
|
|
2139
2191
|
return {
|
|
2140
2192
|
url: `${process.env.MSI_ENDPOINT}?${query.toString()}`,
|
|
@@ -2146,25 +2198,36 @@ function prepareRequestOptions(resource, clientId) {
|
|
|
2146
2198
|
};
|
|
2147
2199
|
}
|
|
2148
2200
|
const appServiceMsi2017 = {
|
|
2149
|
-
async isAvailable() {
|
|
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
|
+
}
|
|
2150
2207
|
const env = process.env;
|
|
2151
2208
|
const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);
|
|
2152
2209
|
if (!result) {
|
|
2153
|
-
logger$9.info(
|
|
2210
|
+
logger$9.info(`${msiName}: Unavailable. The environment variables needed are: MSI_ENDPOINT and MSI_SECRET.`);
|
|
2154
2211
|
}
|
|
2155
2212
|
return result;
|
|
2156
2213
|
},
|
|
2157
|
-
async getToken(
|
|
2158
|
-
|
|
2159
|
-
|
|
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);
|
|
2160
2218
|
}
|
|
2161
2219
|
};
|
|
2162
2220
|
|
|
2163
2221
|
// Copyright (c) Microsoft Corporation.
|
|
2164
|
-
const
|
|
2222
|
+
const msiName$1 = "ManagedIdentityCredential - CloudShellMSI";
|
|
2223
|
+
const logger$a = credentialLogger(msiName$1);
|
|
2165
2224
|
// Cloud Shell MSI doesn't have a special expiresIn parser.
|
|
2166
2225
|
const expiresInParser$1 = undefined;
|
|
2167
|
-
function prepareRequestOptions$1(
|
|
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
|
+
}
|
|
2168
2231
|
const body = {
|
|
2169
2232
|
resource
|
|
2170
2233
|
};
|
|
@@ -2173,12 +2236,13 @@ function prepareRequestOptions$1(resource, clientId) {
|
|
|
2173
2236
|
}
|
|
2174
2237
|
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
2175
2238
|
if (!process.env.MSI_ENDPOINT) {
|
|
2176
|
-
throw new Error(
|
|
2239
|
+
throw new Error(`${msiName$1}: Missing environment variable: MSI_ENDPOINT`);
|
|
2177
2240
|
}
|
|
2241
|
+
const params = new URLSearchParams(body);
|
|
2178
2242
|
return {
|
|
2179
2243
|
url: process.env.MSI_ENDPOINT,
|
|
2180
2244
|
method: "POST",
|
|
2181
|
-
body:
|
|
2245
|
+
body: params.toString(),
|
|
2182
2246
|
headers: coreRestPipeline.createHttpHeaders({
|
|
2183
2247
|
Accept: "application/json",
|
|
2184
2248
|
Metadata: "true",
|
|
@@ -2187,53 +2251,77 @@ function prepareRequestOptions$1(resource, clientId) {
|
|
|
2187
2251
|
};
|
|
2188
2252
|
}
|
|
2189
2253
|
const cloudShellMsi = {
|
|
2190
|
-
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
|
+
}
|
|
2191
2260
|
const result = Boolean(process.env.MSI_ENDPOINT);
|
|
2192
2261
|
if (!result) {
|
|
2193
|
-
logger$a.info(
|
|
2262
|
+
logger$a.info(`${msiName$1}: Unavailable. The environment variable MSI_ENDPOINT is needed.`);
|
|
2194
2263
|
}
|
|
2195
2264
|
return result;
|
|
2196
2265
|
},
|
|
2197
|
-
async getToken(
|
|
2198
|
-
|
|
2199
|
-
|
|
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);
|
|
2200
2270
|
}
|
|
2201
2271
|
};
|
|
2202
2272
|
|
|
2203
2273
|
// Copyright (c) Microsoft Corporation.
|
|
2204
|
-
const
|
|
2274
|
+
const msiName$2 = "ManagedIdentityCredential - IMDS";
|
|
2275
|
+
const logger$b = credentialLogger(msiName$2);
|
|
2205
2276
|
function expiresInParser$2(requestBody) {
|
|
2206
2277
|
if (requestBody.expires_on) {
|
|
2207
2278
|
// Use the expires_on timestamp if it's available
|
|
2208
2279
|
const expires = +requestBody.expires_on * 1000;
|
|
2209
|
-
logger$b.info(
|
|
2280
|
+
logger$b.info(`${msiName$2}: Using expires_on: ${expires} (original value: ${requestBody.expires_on})`);
|
|
2210
2281
|
return expires;
|
|
2211
2282
|
}
|
|
2212
2283
|
else {
|
|
2213
2284
|
// If these aren't possible, use expires_in and calculate a timestamp
|
|
2214
2285
|
const expires = Date.now() + requestBody.expires_in * 1000;
|
|
2215
|
-
logger$b.info(
|
|
2286
|
+
logger$b.info(`${msiName$2}: IMDS using expires_in: ${expires} (original value: ${requestBody.expires_in})`);
|
|
2216
2287
|
return expires;
|
|
2217
2288
|
}
|
|
2218
2289
|
}
|
|
2219
|
-
function prepareRequestOptions$2(
|
|
2290
|
+
function prepareRequestOptions$2(scopes, clientId, options) {
|
|
2220
2291
|
var _a;
|
|
2221
|
-
const
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
}
|
|
2225
|
-
|
|
2226
|
-
|
|
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()}`;
|
|
2227
2310
|
}
|
|
2228
|
-
const query = qs.stringify(queryParameters);
|
|
2229
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"
|
|
2315
|
+
};
|
|
2316
|
+
// Remove the Metadata header to invoke a request error from some IMDS endpoints.
|
|
2317
|
+
if (skipMetadataHeader) {
|
|
2318
|
+
delete rawHeaders.Metadata;
|
|
2319
|
+
}
|
|
2230
2320
|
return {
|
|
2231
|
-
|
|
2321
|
+
// In this case, the `?` should be added in the "query" variable `skipQuery` is not set.
|
|
2322
|
+
url: `${url}${query}`,
|
|
2232
2323
|
method: "GET",
|
|
2233
|
-
headers: coreRestPipeline.createHttpHeaders(
|
|
2234
|
-
Accept: "application/json",
|
|
2235
|
-
Metadata: "true"
|
|
2236
|
-
})
|
|
2324
|
+
headers: coreRestPipeline.createHttpHeaders(rawHeaders)
|
|
2237
2325
|
};
|
|
2238
2326
|
}
|
|
2239
2327
|
// 800ms -> 1600ms -> 3200ms
|
|
@@ -2243,24 +2331,23 @@ const imdsMsiRetryConfig = {
|
|
|
2243
2331
|
intervalIncrement: 2
|
|
2244
2332
|
};
|
|
2245
2333
|
const imdsMsi = {
|
|
2246
|
-
async isAvailable(
|
|
2334
|
+
async isAvailable(scopes, identityClient, clientId, getTokenOptions) {
|
|
2247
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
|
+
}
|
|
2248
2341
|
const { span, updatedOptions: options } = createSpan("ManagedIdentityCredential-pingImdsEndpoint", getTokenOptions);
|
|
2249
2342
|
// if the PodIdenityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist
|
|
2250
2343
|
if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) {
|
|
2251
2344
|
return true;
|
|
2252
2345
|
}
|
|
2253
|
-
const requestOptions = prepareRequestOptions$2(resource, clientId
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
requestOptions.headers.delete("Metadata");
|
|
2259
|
-
}
|
|
2260
|
-
requestOptions.tracingOptions = {
|
|
2261
|
-
spanOptions: options.tracingOptions && options.tracingOptions.spanOptions,
|
|
2262
|
-
tracingContext: options.tracingOptions && options.tracingOptions.tracingContext
|
|
2263
|
-
};
|
|
2346
|
+
const requestOptions = prepareRequestOptions$2(resource, clientId, {
|
|
2347
|
+
skipMetadataHeader: true,
|
|
2348
|
+
skipQuery: true
|
|
2349
|
+
});
|
|
2350
|
+
requestOptions.tracingOptions = options.tracingOptions;
|
|
2264
2351
|
try {
|
|
2265
2352
|
// Create a request with a timeout since we expect that
|
|
2266
2353
|
// not having a "Metadata" header should cause an error to be
|
|
@@ -2270,18 +2357,19 @@ const imdsMsi = {
|
|
|
2270
2357
|
// This MSI uses the imdsEndpoint to get the token, which only uses http://
|
|
2271
2358
|
request.allowInsecureConnection = true;
|
|
2272
2359
|
try {
|
|
2273
|
-
logger$b.info(
|
|
2360
|
+
logger$b.info(`${msiName$2}: Pinging the Azure IMDS endpoint`);
|
|
2274
2361
|
await identityClient.sendRequest(request);
|
|
2275
2362
|
}
|
|
2276
2363
|
catch (err) {
|
|
2277
2364
|
if ((err.name === "RestError" && err.code === coreRestPipeline.RestError.REQUEST_SEND_ERROR) ||
|
|
2278
2365
|
err.name === "AbortError" ||
|
|
2366
|
+
err.code === "ENETUNREACH" || // Network unreachable
|
|
2279
2367
|
err.code === "ECONNREFUSED" || // connection refused
|
|
2280
2368
|
err.code === "EHOSTDOWN" // host is down
|
|
2281
2369
|
) {
|
|
2282
2370
|
// If the request failed, or Node.js was unable to establish a connection,
|
|
2283
2371
|
// or the host was down, we'll assume the IMDS endpoint isn't available.
|
|
2284
|
-
logger$b.info(
|
|
2372
|
+
logger$b.info(`${msiName$2}: The Azure IMDS endpoint is unavailable`);
|
|
2285
2373
|
span.setStatus({
|
|
2286
2374
|
code: coreTracing.SpanStatusCode.ERROR,
|
|
2287
2375
|
message: err.message
|
|
@@ -2290,13 +2378,13 @@ const imdsMsi = {
|
|
|
2290
2378
|
}
|
|
2291
2379
|
}
|
|
2292
2380
|
// If we received any response, the endpoint is available
|
|
2293
|
-
logger$b.info(
|
|
2381
|
+
logger$b.info(`${msiName$2}: The Azure IMDS endpoint is available`);
|
|
2294
2382
|
return true;
|
|
2295
2383
|
}
|
|
2296
2384
|
catch (err) {
|
|
2297
2385
|
// createWebResource failed.
|
|
2298
2386
|
// This error should bubble up to the user.
|
|
2299
|
-
logger$b.info(
|
|
2387
|
+
logger$b.info(`${msiName$2}: Error when creating the WebResource for the Azure IMDS endpoint: ${err.message}`);
|
|
2300
2388
|
span.setStatus({
|
|
2301
2389
|
code: coreTracing.SpanStatusCode.ERROR,
|
|
2302
2390
|
message: err.message
|
|
@@ -2307,12 +2395,13 @@ const imdsMsi = {
|
|
|
2307
2395
|
span.end();
|
|
2308
2396
|
}
|
|
2309
2397
|
},
|
|
2310
|
-
async getToken(
|
|
2311
|
-
|
|
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.`);
|
|
2312
2401
|
let nextDelayInMs = imdsMsiRetryConfig.startDelayInMs;
|
|
2313
2402
|
for (let retries = 0; retries < imdsMsiRetryConfig.maxRetries; retries++) {
|
|
2314
2403
|
try {
|
|
2315
|
-
return await msiGenericGetToken(identityClient, prepareRequestOptions$2(
|
|
2404
|
+
return await msiGenericGetToken(identityClient, prepareRequestOptions$2(scopes, clientId), expiresInParser$2, getTokenOptions);
|
|
2316
2405
|
}
|
|
2317
2406
|
catch (error) {
|
|
2318
2407
|
if (error.statusCode === 404) {
|
|
@@ -2323,15 +2412,20 @@ const imdsMsi = {
|
|
|
2323
2412
|
throw error;
|
|
2324
2413
|
}
|
|
2325
2414
|
}
|
|
2326
|
-
throw new AuthenticationError(404,
|
|
2415
|
+
throw new AuthenticationError(404, `${msiName$2}: Failed to retrieve IMDS token after ${imdsMsiRetryConfig.maxRetries} retries.`);
|
|
2327
2416
|
}
|
|
2328
2417
|
};
|
|
2329
2418
|
|
|
2330
2419
|
// Copyright (c) Microsoft Corporation.
|
|
2331
|
-
const
|
|
2420
|
+
const msiName$3 = "ManagedIdentityCredential - Azure Arc MSI";
|
|
2421
|
+
const logger$c = credentialLogger(msiName$3);
|
|
2332
2422
|
// Azure Arc MSI doesn't have a special expiresIn parser.
|
|
2333
2423
|
const expiresInParser$3 = undefined;
|
|
2334
|
-
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
|
+
}
|
|
2335
2429
|
const queryParameters = {
|
|
2336
2430
|
resource,
|
|
2337
2431
|
"api-version": azureArcAPIVersion
|
|
@@ -2339,7 +2433,7 @@ function prepareRequestOptions$3(resource) {
|
|
|
2339
2433
|
const query = new URLSearchParams(queryParameters);
|
|
2340
2434
|
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
2341
2435
|
if (!process.env.IDENTITY_ENDPOINT) {
|
|
2342
|
-
throw new Error(
|
|
2436
|
+
throw new Error(`${msiName$3}: Missing environment variable: IDENTITY_ENDPOINT`);
|
|
2343
2437
|
}
|
|
2344
2438
|
return coreRestPipeline.createPipelineRequest({
|
|
2345
2439
|
// Should be similar to: http://localhost:40342/metadata/identity/oauth2/token
|
|
@@ -2352,7 +2446,7 @@ function prepareRequestOptions$3(resource) {
|
|
|
2352
2446
|
});
|
|
2353
2447
|
}
|
|
2354
2448
|
// Since "fs"'s readFileSync locks the thread, and to avoid extra dependencies.
|
|
2355
|
-
function readFileAsync(path, options) {
|
|
2449
|
+
function readFileAsync$1(path, options) {
|
|
2356
2450
|
return new Promise((resolve, reject) => fs.readFile(path, options, (err, data) => {
|
|
2357
2451
|
if (err) {
|
|
2358
2452
|
reject(err);
|
|
@@ -2367,7 +2461,7 @@ async function filePathRequest(identityClient, requestPrepareOptions) {
|
|
|
2367
2461
|
if (response.bodyAsText) {
|
|
2368
2462
|
message = ` Response: ${response.bodyAsText}`;
|
|
2369
2463
|
}
|
|
2370
|
-
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}`);
|
|
2371
2465
|
}
|
|
2372
2466
|
const authHeader = response.headers.get("www-authenticate") || "";
|
|
2373
2467
|
try {
|
|
@@ -2378,32 +2472,190 @@ async function filePathRequest(identityClient, requestPrepareOptions) {
|
|
|
2378
2472
|
}
|
|
2379
2473
|
}
|
|
2380
2474
|
const arcMsi = {
|
|
2381
|
-
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
|
+
}
|
|
2382
2481
|
const result = Boolean(process.env.IMDS_ENDPOINT && process.env.IDENTITY_ENDPOINT);
|
|
2383
2482
|
if (!result) {
|
|
2384
|
-
logger$c.info(
|
|
2483
|
+
logger$c.info(`${msiName$3}: The environment variables needed are: IMDS_ENDPOINT and IDENTITY_ENDPOINT`);
|
|
2385
2484
|
}
|
|
2386
2485
|
return result;
|
|
2387
2486
|
},
|
|
2388
|
-
async getToken(
|
|
2487
|
+
async getToken(configuration, getTokenOptions = {}) {
|
|
2389
2488
|
var _a;
|
|
2390
|
-
|
|
2489
|
+
const { identityClient, scopes, clientId } = configuration;
|
|
2490
|
+
logger$c.info(`${msiName$3}: Authenticating.`);
|
|
2391
2491
|
if (clientId) {
|
|
2392
|
-
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.`);
|
|
2393
2493
|
}
|
|
2394
|
-
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 });
|
|
2395
2495
|
const filePath = await filePathRequest(identityClient, requestOptions);
|
|
2396
2496
|
if (!filePath) {
|
|
2397
|
-
throw new Error(
|
|
2497
|
+
throw new Error(`${msiName$3}: Failed to find the token file.`);
|
|
2398
2498
|
}
|
|
2399
|
-
const key = await readFileAsync(filePath, { encoding: "utf-8" });
|
|
2499
|
+
const key = await readFileAsync$1(filePath, { encoding: "utf-8" });
|
|
2400
2500
|
(_a = requestOptions.headers) === null || _a === void 0 ? void 0 : _a.set("Authorization", `Basic ${key}`);
|
|
2401
2501
|
return msiGenericGetToken(identityClient, requestOptions, expiresInParser$3, getTokenOptions);
|
|
2402
2502
|
}
|
|
2403
2503
|
};
|
|
2404
2504
|
|
|
2405
2505
|
// Copyright (c) Microsoft Corporation.
|
|
2406
|
-
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");
|
|
2407
2659
|
/**
|
|
2408
2660
|
* Attempts authentication using a managed identity that has been assigned
|
|
2409
2661
|
* to the deployment environment. This authentication type works in Azure VMs,
|
|
@@ -2430,15 +2682,13 @@ class ManagedIdentityCredential {
|
|
|
2430
2682
|
this.identityClient = new IdentityClient(clientIdOrOptions);
|
|
2431
2683
|
}
|
|
2432
2684
|
}
|
|
2433
|
-
async cachedAvailableMSI(
|
|
2685
|
+
async cachedAvailableMSI(scopes, clientId, getTokenOptions) {
|
|
2434
2686
|
if (this.cachedMSI) {
|
|
2435
2687
|
return this.cachedMSI;
|
|
2436
2688
|
}
|
|
2437
|
-
|
|
2438
|
-
// which is necessary since Service Fabric only provides self-signed certificates on their Identity Endpoint.
|
|
2439
|
-
const MSIs = [appServiceMsi2017, cloudShellMsi, arcMsi, imdsMsi];
|
|
2689
|
+
const MSIs = [fabricMsi, appServiceMsi2017, cloudShellMsi, arcMsi, tokenExchangeMsi(), imdsMsi];
|
|
2440
2690
|
for (const msi of MSIs) {
|
|
2441
|
-
if (await msi.isAvailable(this.identityClient,
|
|
2691
|
+
if (await msi.isAvailable(scopes, this.identityClient, clientId, getTokenOptions)) {
|
|
2442
2692
|
this.cachedMSI = msi;
|
|
2443
2693
|
return msi;
|
|
2444
2694
|
}
|
|
@@ -2446,12 +2696,15 @@ class ManagedIdentityCredential {
|
|
|
2446
2696
|
throw new CredentialUnavailableError("ManagedIdentityCredential - No MSI credential available");
|
|
2447
2697
|
}
|
|
2448
2698
|
async authenticateManagedIdentity(scopes, clientId, getTokenOptions) {
|
|
2449
|
-
const resource = mapScopesToResource(scopes);
|
|
2450
2699
|
const { span, updatedOptions } = createSpan("ManagedIdentityCredential-authenticateManagedIdentity", getTokenOptions);
|
|
2451
2700
|
try {
|
|
2452
2701
|
// Determining the available MSI, and avoiding checking for other MSIs while the program is running.
|
|
2453
|
-
const availableMSI = await this.cachedAvailableMSI(
|
|
2454
|
-
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);
|
|
2455
2708
|
}
|
|
2456
2709
|
catch (err) {
|
|
2457
2710
|
span.setStatus({
|
|
@@ -2475,7 +2728,7 @@ class ManagedIdentityCredential {
|
|
|
2475
2728
|
*/
|
|
2476
2729
|
async getToken(scopes, options) {
|
|
2477
2730
|
let result = null;
|
|
2478
|
-
const { span, updatedOptions } = createSpan("ManagedIdentityCredential
|
|
2731
|
+
const { span, updatedOptions } = createSpan("ManagedIdentityCredential.getToken", options);
|
|
2479
2732
|
try {
|
|
2480
2733
|
// isEndpointAvailable can be true, false, or null,
|
|
2481
2734
|
// If it's null, it means we don't yet know whether
|
|
@@ -2490,7 +2743,7 @@ class ManagedIdentityCredential {
|
|
|
2490
2743
|
// It also means that the endpoint answered with either 200 or 201 (see the sendTokenRequest method),
|
|
2491
2744
|
// yet we had no access token. For this reason, we'll throw once with a specific message:
|
|
2492
2745
|
const error = new CredentialUnavailableError("The managed identity endpoint was reached, yet no tokens were received.");
|
|
2493
|
-
logger$
|
|
2746
|
+
logger$f.getToken.info(formatError(scopes, error));
|
|
2494
2747
|
throw error;
|
|
2495
2748
|
}
|
|
2496
2749
|
// Since `authenticateManagedIdentity` didn't throw, and the result was not null,
|
|
@@ -2502,10 +2755,10 @@ class ManagedIdentityCredential {
|
|
|
2502
2755
|
// We've previously determined that the endpoint was unavailable,
|
|
2503
2756
|
// either because it was unreachable or permanently unable to authenticate.
|
|
2504
2757
|
const error = new CredentialUnavailableError("The managed identity endpoint is not currently available");
|
|
2505
|
-
logger$
|
|
2758
|
+
logger$f.getToken.info(formatError(scopes, error));
|
|
2506
2759
|
throw error;
|
|
2507
2760
|
}
|
|
2508
|
-
logger$
|
|
2761
|
+
logger$f.getToken.info(formatSuccess(scopes));
|
|
2509
2762
|
return result;
|
|
2510
2763
|
}
|
|
2511
2764
|
catch (err) {
|
|
@@ -2526,21 +2779,21 @@ class ManagedIdentityCredential {
|
|
|
2526
2779
|
// If either the network is unreachable,
|
|
2527
2780
|
// we can safely assume the credential is unavailable.
|
|
2528
2781
|
if (err.code === "ENETUNREACH") {
|
|
2529
|
-
const error = new CredentialUnavailableError(
|
|
2530
|
-
logger$
|
|
2782
|
+
const error = new CredentialUnavailableError(`ManagedIdentityCredential is unavailable. Network unreachable. Message: ${err.message}`);
|
|
2783
|
+
logger$f.getToken.info(formatError(scopes, error));
|
|
2531
2784
|
throw error;
|
|
2532
2785
|
}
|
|
2533
2786
|
// If either the host was unreachable,
|
|
2534
2787
|
// we can safely assume the credential is unavailable.
|
|
2535
2788
|
if (err.code === "EHOSTUNREACH") {
|
|
2536
|
-
const error = new CredentialUnavailableError(
|
|
2537
|
-
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));
|
|
2538
2791
|
throw error;
|
|
2539
2792
|
}
|
|
2540
2793
|
// If err.statusCode has a value of 400, it comes from sendTokenRequest,
|
|
2541
2794
|
// and it means that the endpoint is working, but that no identity is available.
|
|
2542
2795
|
if (err.statusCode === 400) {
|
|
2543
|
-
throw new CredentialUnavailableError(
|
|
2796
|
+
throw new CredentialUnavailableError(`ManagedIdentityCredential: The managed identity endpoint is indicating there's no available identity. Message: ${err.message}`);
|
|
2544
2797
|
}
|
|
2545
2798
|
// If the error has no status code, we can assume there was no available identity.
|
|
2546
2799
|
// This will throw silently during any ChainedTokenCredential.
|
|
@@ -2588,36 +2841,37 @@ const defaultCredentials = [
|
|
|
2588
2841
|
];
|
|
2589
2842
|
/**
|
|
2590
2843
|
* Provides a default {@link ChainedTokenCredential} configuration that should
|
|
2591
|
-
* work for most applications that use the Azure SDK.
|
|
2592
|
-
* types will be tried, in order:
|
|
2593
|
-
*
|
|
2594
|
-
* - {@link EnvironmentCredential}
|
|
2595
|
-
* - {@link ManagedIdentityCredential}
|
|
2596
|
-
* - {@link VisualStudioCodeCredential}
|
|
2597
|
-
* - {@link AzureCliCredential}
|
|
2598
|
-
* - {@link AzurePowerShellCredential}
|
|
2599
|
-
*
|
|
2600
|
-
* Consult the documentation of these credential types for more information
|
|
2601
|
-
* on how they attempt authentication.
|
|
2602
|
-
*
|
|
2603
|
-
* **Note**: `VisualStudioCodeCredential` is provided by an extension package:
|
|
2604
|
-
* `@azure/identity-vscode`. If this package is not installed and registered
|
|
2605
|
-
* using the extension API (`useIdentityExtension`), then authentication using
|
|
2606
|
-
* `VisualStudioCodeCredential` will not be available.
|
|
2607
|
-
*
|
|
2608
|
-
* Azure Identity extensions may add credential types to the default credential
|
|
2609
|
-
* stack.
|
|
2844
|
+
* work for most applications that use the Azure SDK.
|
|
2610
2845
|
*/
|
|
2611
2846
|
class DefaultAzureCredential extends ChainedTokenCredential {
|
|
2612
2847
|
/**
|
|
2613
2848
|
* Creates an instance of the DefaultAzureCredential class.
|
|
2614
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
|
+
*
|
|
2615
2869
|
* @param options - Optional parameters. See {@link DefaultAzureCredentialOptions}.
|
|
2616
2870
|
*/
|
|
2617
2871
|
constructor(options) {
|
|
2618
2872
|
super(...defaultCredentials.map((ctor) => new ctor(options)));
|
|
2619
2873
|
this.UnavailableMessage =
|
|
2620
|
-
"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.";
|
|
2621
2875
|
}
|
|
2622
2876
|
}
|
|
2623
2877
|
|
|
@@ -2765,29 +3019,29 @@ class MsalOpenBrowser extends MsalNode {
|
|
|
2765
3019
|
}
|
|
2766
3020
|
|
|
2767
3021
|
// Copyright (c) Microsoft Corporation.
|
|
2768
|
-
const logger$
|
|
3022
|
+
const logger$g = credentialLogger("InteractiveBrowserCredential");
|
|
2769
3023
|
/**
|
|
2770
3024
|
* Enables authentication to Azure Active Directory inside of the web browser
|
|
2771
3025
|
* using the interactive login flow.
|
|
2772
|
-
*
|
|
2773
|
-
* This credential uses the [Authorization Code Flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-auth-code-flow).
|
|
2774
|
-
* On Node.js, it will open a browser window while it listens for a redirect response from the authentication service.
|
|
2775
|
-
* 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.
|
|
2776
|
-
*
|
|
2777
|
-
* 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.
|
|
2778
|
-
* 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).
|
|
2779
3026
|
*/
|
|
2780
3027
|
class InteractiveBrowserCredential {
|
|
2781
3028
|
/**
|
|
2782
3029
|
* Creates an instance of InteractiveBrowserCredential with the details needed.
|
|
2783
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
|
+
*
|
|
2784
3038
|
* @param options - Options for configuring the client which makes the authentication requests.
|
|
2785
3039
|
*/
|
|
2786
3040
|
constructor(options = {}) {
|
|
2787
3041
|
const redirectUri = typeof options.redirectUri === "function"
|
|
2788
3042
|
? options.redirectUri()
|
|
2789
3043
|
: options.redirectUri || "http://localhost";
|
|
2790
|
-
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,
|
|
2791
3045
|
redirectUri }));
|
|
2792
3046
|
this.disableAutomaticAuthentication = options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication;
|
|
2793
3047
|
}
|
|
@@ -2865,7 +3119,7 @@ class MsalDeviceCode extends MsalNode {
|
|
|
2865
3119
|
}
|
|
2866
3120
|
|
|
2867
3121
|
// Copyright (c) Microsoft Corporation.
|
|
2868
|
-
const logger$
|
|
3122
|
+
const logger$h = credentialLogger("DeviceCodeCredential");
|
|
2869
3123
|
/**
|
|
2870
3124
|
* Method that logs the user code from the DeviceCodeCredential.
|
|
2871
3125
|
* @param deviceCodeInfo - The device code.
|
|
@@ -2882,10 +3136,24 @@ class DeviceCodeCredential {
|
|
|
2882
3136
|
* Creates an instance of DeviceCodeCredential with the details needed
|
|
2883
3137
|
* to initiate the device code authorization flow with Azure Active Directory.
|
|
2884
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
|
+
*
|
|
2885
3153
|
* @param options - Options for configuring the client which makes the authentication requests.
|
|
2886
3154
|
*/
|
|
2887
3155
|
constructor(options) {
|
|
2888
|
-
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 || {} }));
|
|
2889
3157
|
this.disableAutomaticAuthentication = options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication;
|
|
2890
3158
|
}
|
|
2891
3159
|
/**
|
|
@@ -2926,7 +3194,45 @@ class DeviceCodeCredential {
|
|
|
2926
3194
|
}
|
|
2927
3195
|
|
|
2928
3196
|
// Copyright (c) Microsoft Corporation.
|
|
2929
|
-
|
|
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");
|
|
2930
3236
|
/**
|
|
2931
3237
|
* Enables authentication to Azure Active Directory using an authorization code
|
|
2932
3238
|
* that was obtained through the authorization code flow, described in more detail
|
|
@@ -2940,26 +3246,23 @@ class AuthorizationCodeCredential {
|
|
|
2940
3246
|
* @internal
|
|
2941
3247
|
*/
|
|
2942
3248
|
constructor(tenantId, clientId, clientSecretOrAuthorizationCode, authorizationCodeOrRedirectUri, redirectUriOrOptions, options) {
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
this.clientId = clientId;
|
|
2946
|
-
this.tenantId = tenantId;
|
|
3249
|
+
checkTenantId(logger$i, tenantId);
|
|
3250
|
+
let clientSecret = clientSecretOrAuthorizationCode;
|
|
2947
3251
|
if (typeof redirectUriOrOptions === "string") {
|
|
2948
3252
|
// the clientId+clientSecret constructor
|
|
2949
|
-
this.clientSecret = clientSecretOrAuthorizationCode;
|
|
2950
3253
|
this.authorizationCode = authorizationCodeOrRedirectUri;
|
|
2951
3254
|
this.redirectUri = redirectUriOrOptions;
|
|
2952
3255
|
// options okay
|
|
2953
3256
|
}
|
|
2954
3257
|
else {
|
|
2955
3258
|
// clientId only
|
|
2956
|
-
this.clientSecret = undefined;
|
|
2957
3259
|
this.authorizationCode = clientSecretOrAuthorizationCode;
|
|
2958
3260
|
this.redirectUri = authorizationCodeOrRedirectUri;
|
|
3261
|
+
clientSecret = undefined;
|
|
2959
3262
|
options = redirectUriOrOptions;
|
|
2960
3263
|
}
|
|
2961
|
-
this.
|
|
2962
|
-
|
|
3264
|
+
this.msalFlow = new MsalAuthorizationCode(Object.assign(Object.assign({}, options), { clientSecret,
|
|
3265
|
+
clientId, tokenCredentialOptions: options || {}, logger: logger$i, redirectUri: this.redirectUri, authorizationCode: this.authorizationCode }));
|
|
2963
3266
|
}
|
|
2964
3267
|
/**
|
|
2965
3268
|
* Authenticates with Azure Active Directory and returns an access token if successful.
|
|
@@ -2969,100 +3272,116 @@ class AuthorizationCodeCredential {
|
|
|
2969
3272
|
* @param options - The options used to configure any requests this
|
|
2970
3273
|
* TokenCredential implementation might make.
|
|
2971
3274
|
*/
|
|
2972
|
-
async getToken(scopes, options) {
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
this.
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
const
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
3006
|
-
}),
|
|
3007
|
-
tracingOptions: {
|
|
3008
|
-
spanOptions: (_a = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _a === void 0 ? void 0 : _a.spanOptions,
|
|
3009
|
-
tracingContext: (_b = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _b === void 0 ? void 0 : _b.tracingContext
|
|
3010
|
-
}
|
|
3011
|
-
});
|
|
3012
|
-
tokenResponse = await this.identityClient.sendTokenRequest(pipelineRequest, (response) => new Date(response === null || response === void 0 ? void 0 : response.expires_on).getTime());
|
|
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
|
+
};
|
|
3013
3308
|
}
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
if (!token) {
|
|
3018
|
-
throw new CredentialUnavailableError("Failed to retrieve a valid token");
|
|
3309
|
+
catch (error) {
|
|
3310
|
+
this.logger.info(formatError("", error));
|
|
3311
|
+
throw error;
|
|
3019
3312
|
}
|
|
3020
|
-
return token;
|
|
3021
3313
|
}
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
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
|
|
3026
3326
|
});
|
|
3027
|
-
|
|
3028
|
-
throw err;
|
|
3327
|
+
return this.handleResult(scopes, this.clientId, result || undefined);
|
|
3029
3328
|
}
|
|
3030
|
-
|
|
3031
|
-
|
|
3329
|
+
catch (err) {
|
|
3330
|
+
throw this.handleError(scopes, err, options);
|
|
3032
3331
|
}
|
|
3033
3332
|
}
|
|
3034
3333
|
}
|
|
3035
3334
|
|
|
3036
3335
|
// Copyright (c) Microsoft Corporation.
|
|
3037
|
-
const
|
|
3038
|
-
|
|
3039
|
-
DefaultManagedIdentityCredential
|
|
3040
|
-
];
|
|
3336
|
+
const credentialName$1 = "OnBehalfOfCredential";
|
|
3337
|
+
const logger$j = credentialLogger(credentialName$1);
|
|
3041
3338
|
/**
|
|
3042
|
-
*
|
|
3043
|
-
* work for most applications that use the Azure SDK. The following credential
|
|
3044
|
-
* types will be tried, in order:
|
|
3045
|
-
*
|
|
3046
|
-
* - {@link EnvironmentCredential}
|
|
3047
|
-
* - {@link ManagedIdentityCredential}
|
|
3048
|
-
|
|
3049
|
-
*
|
|
3050
|
-
* Consult the documentation of these credential types for more information
|
|
3051
|
-
* on how they attempt authentication.
|
|
3052
|
-
*
|
|
3053
|
-
* Azure Identity extensions may add credential types to the default credential
|
|
3054
|
-
* stack.
|
|
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).
|
|
3055
3340
|
*/
|
|
3056
|
-
class
|
|
3341
|
+
class OnBehalfOfCredential {
|
|
3057
3342
|
/**
|
|
3058
|
-
* Creates an instance of the
|
|
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
|
+
* ```
|
|
3059
3360
|
*
|
|
3060
|
-
* @param options - Optional parameters
|
|
3361
|
+
* @param options - Optional parameters, generally common across credentials.
|
|
3061
3362
|
*/
|
|
3062
3363
|
constructor(options) {
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
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.`);
|
|
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
|
+
});
|
|
3066
3385
|
}
|
|
3067
3386
|
}
|
|
3068
3387
|
|
|
@@ -3076,7 +3395,6 @@ function getDefaultAzureCredential() {
|
|
|
3076
3395
|
|
|
3077
3396
|
exports.AggregateAuthenticationError = AggregateAuthenticationError;
|
|
3078
3397
|
exports.AggregateAuthenticationErrorName = AggregateAuthenticationErrorName;
|
|
3079
|
-
exports.ApplicationCredential = ApplicationCredential;
|
|
3080
3398
|
exports.AuthenticationError = AuthenticationError;
|
|
3081
3399
|
exports.AuthenticationErrorName = AuthenticationErrorName;
|
|
3082
3400
|
exports.AuthenticationRequiredError = AuthenticationRequiredError;
|
|
@@ -3093,11 +3411,12 @@ exports.DeviceCodeCredential = DeviceCodeCredential;
|
|
|
3093
3411
|
exports.EnvironmentCredential = EnvironmentCredential;
|
|
3094
3412
|
exports.InteractiveBrowserCredential = InteractiveBrowserCredential;
|
|
3095
3413
|
exports.ManagedIdentityCredential = ManagedIdentityCredential;
|
|
3414
|
+
exports.OnBehalfOfCredential = OnBehalfOfCredential;
|
|
3096
3415
|
exports.UsernamePasswordCredential = UsernamePasswordCredential;
|
|
3097
3416
|
exports.VisualStudioCodeCredential = VisualStudioCodeCredential;
|
|
3098
3417
|
exports.deserializeAuthenticationRecord = deserializeAuthenticationRecord;
|
|
3099
3418
|
exports.getDefaultAzureCredential = getDefaultAzureCredential;
|
|
3100
3419
|
exports.logger = logger;
|
|
3101
3420
|
exports.serializeAuthenticationRecord = serializeAuthenticationRecord;
|
|
3102
|
-
exports.
|
|
3421
|
+
exports.useIdentityPlugin = useIdentityPlugin;
|
|
3103
3422
|
//# sourceMappingURL=index.js.map
|