@azure/identity 4.4.0 → 4.5.0-alpha.20240813.2
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +22 -1
- package/dist/index.js +441 -812
- package/dist/index.js.map +1 -1
- package/dist-esm/src/client/identityClient.js +8 -2
- package/dist-esm/src/client/identityClient.js.map +1 -1
- package/dist-esm/src/constants.js +1 -1
- package/dist-esm/src/constants.js.map +1 -1
- package/dist-esm/src/credentials/azurePipelinesCredential.js +50 -26
- package/dist-esm/src/credentials/azurePipelinesCredential.js.map +1 -1
- package/dist-esm/src/credentials/azurePowerShellCredential.js +63 -19
- package/dist-esm/src/credentials/azurePowerShellCredential.js.map +1 -1
- package/dist-esm/src/credentials/clientAssertionCredential.js +9 -2
- package/dist-esm/src/credentials/clientAssertionCredential.js.map +1 -1
- package/dist-esm/src/credentials/clientCertificateCredential.js +35 -27
- package/dist-esm/src/credentials/clientCertificateCredential.js.map +1 -1
- package/dist-esm/src/credentials/clientSecretCredential.js +9 -2
- package/dist-esm/src/credentials/clientSecretCredential.js.map +1 -1
- package/dist-esm/src/credentials/deviceCodeCredential.js +1 -1
- package/dist-esm/src/credentials/deviceCodeCredential.js.map +1 -1
- package/dist-esm/src/credentials/deviceCodeCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/environmentCredential.js +11 -1
- package/dist-esm/src/credentials/environmentCredential.js.map +1 -1
- package/dist-esm/src/credentials/interactiveBrowserCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/interactiveBrowserCredential.js +1 -1
- 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/imdsRetryPolicy.js +37 -0
- package/dist-esm/src/credentials/managedIdentityCredential/imdsRetryPolicy.js.map +1 -0
- package/dist-esm/src/credentials/managedIdentityCredential/index.js +6 -2
- package/dist-esm/src/credentials/managedIdentityCredential/index.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/legacyMsiProvider.js +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/legacyMsiProvider.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/msalMsiProvider.js +195 -0
- package/dist-esm/src/credentials/managedIdentityCredential/msalMsiProvider.js.map +1 -0
- package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js +19 -22
- package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js.map +1 -1
- package/dist-esm/src/credentials/onBehalfOfCredential.js +16 -9
- package/dist-esm/src/credentials/onBehalfOfCredential.js.map +1 -1
- package/dist-esm/src/credentials/usernamePasswordCredential.js +13 -3
- package/dist-esm/src/credentials/usernamePasswordCredential.js.map +1 -1
- package/dist-esm/src/credentials/workloadIdentityCredential.js +16 -6
- package/dist-esm/src/credentials/workloadIdentityCredential.js.map +1 -1
- package/dist-esm/src/errors.js +12 -7
- package/dist-esm/src/errors.js.map +1 -1
- package/dist-esm/src/msal/browserFlows/flows.js.map +1 -0
- package/dist-esm/src/msal/browserFlows/msalBrowserCommon.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalClient.js +8 -1
- package/dist-esm/src/msal/nodeFlows/msalClient.js.map +1 -1
- package/package.json +4 -4
- package/types/identity.d.ts +26 -8
- package/dist-esm/src/msal/flows.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js +0 -47
- package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalClientAssertion.js +0 -42
- package/dist-esm/src/msal/nodeFlows/msalClientAssertion.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js +0 -112
- package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalClientSecret.js +0 -33
- package/dist-esm/src/msal/nodeFlows/msalClientSecret.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalDeviceCode.js +0 -35
- package/dist-esm/src/msal/nodeFlows/msalDeviceCode.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalNodeCommon.js +0 -323
- package/dist-esm/src/msal/nodeFlows/msalNodeCommon.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js +0 -58
- package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js +0 -113
- package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalUsernamePassword.js +0 -33
- package/dist-esm/src/msal/nodeFlows/msalUsernamePassword.js.map +0 -1
- /package/dist-esm/src/msal/{flows.js → browserFlows/flows.js} +0 -0
package/dist/index.js
CHANGED
@@ -2,24 +2,22 @@
|
|
2
2
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
4
4
|
|
5
|
-
var logger$
|
5
|
+
var logger$m = require('@azure/logger');
|
6
6
|
var coreClient = require('@azure/core-client');
|
7
7
|
var coreUtil = require('@azure/core-util');
|
8
8
|
var coreRestPipeline = require('@azure/core-rest-pipeline');
|
9
|
-
var abortController = require('@azure/abort-controller');
|
10
9
|
var coreTracing = require('@azure/core-tracing');
|
11
10
|
var fs = require('fs');
|
12
11
|
var os = require('os');
|
13
12
|
var path = require('path');
|
13
|
+
var abortController = require('@azure/abort-controller');
|
14
14
|
var msalCommon = require('@azure/msal-node');
|
15
|
-
var fs$1 = require('node:fs');
|
16
|
-
var https = require('https');
|
17
15
|
var open = require('open');
|
18
16
|
var promises = require('fs/promises');
|
19
17
|
var child_process = require('child_process');
|
20
18
|
var crypto = require('crypto');
|
21
|
-
var promises$1 = require('node:fs/promises');
|
22
19
|
var node_crypto = require('node:crypto');
|
20
|
+
var promises$1 = require('node:fs/promises');
|
23
21
|
|
24
22
|
function _interopNamespaceDefault(e) {
|
25
23
|
var n = Object.create(null);
|
@@ -46,7 +44,7 @@ var child_process__namespace = /*#__PURE__*/_interopNamespaceDefault(child_proce
|
|
46
44
|
/**
|
47
45
|
* Current version of the `@azure/identity` package.
|
48
46
|
*/
|
49
|
-
const SDK_VERSION = `4.
|
47
|
+
const SDK_VERSION = `4.5.0-beta.2`;
|
50
48
|
/**
|
51
49
|
* The default client ID for authentication
|
52
50
|
* @internal
|
@@ -196,7 +194,7 @@ const msalPlugins = {
|
|
196
194
|
/**
|
197
195
|
* The AzureLogger used for all clients within the identity package
|
198
196
|
*/
|
199
|
-
const logger$
|
197
|
+
const logger$l = logger$m.createClientLogger("identity");
|
200
198
|
/**
|
201
199
|
* 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.
|
202
200
|
* @param supportedEnvVars - List of environment variable names
|
@@ -236,7 +234,7 @@ function formatError(scope, error) {
|
|
236
234
|
* `[title] => [message]`
|
237
235
|
*
|
238
236
|
*/
|
239
|
-
function credentialLoggerInstance(title, parent, log = logger$
|
237
|
+
function credentialLoggerInstance(title, parent, log = logger$l) {
|
240
238
|
const fullTitle = parent ? `${parent.fullTitle} ${title}` : title;
|
241
239
|
function info(message) {
|
242
240
|
log.info(`${fullTitle} =>`, message);
|
@@ -269,7 +267,7 @@ function credentialLoggerInstance(title, parent, log = logger$q) {
|
|
269
267
|
* `[title] => getToken() => [message]`
|
270
268
|
*
|
271
269
|
*/
|
272
|
-
function credentialLogger(title, log = logger$
|
270
|
+
function credentialLogger(title, log = logger$l) {
|
273
271
|
const credLogger = credentialLoggerInstance(title, undefined, log);
|
274
272
|
return Object.assign(Object.assign({}, credLogger), { parent: log, getToken: credentialLoggerInstance("=> getToken()", credLogger, log) });
|
275
273
|
}
|
@@ -291,8 +289,9 @@ const CredentialUnavailableErrorName = "CredentialUnavailableError";
|
|
291
289
|
* an error that should halt the chain, it's caught and the chain continues
|
292
290
|
*/
|
293
291
|
class CredentialUnavailableError extends Error {
|
294
|
-
constructor(message) {
|
295
|
-
|
292
|
+
constructor(message, options) {
|
293
|
+
// @ts-expect-error - TypeScript does not recognize this until we use ES2022 as the target; however, all our major runtimes do support the `cause` property
|
294
|
+
super(message, options);
|
296
295
|
this.name = CredentialUnavailableErrorName;
|
297
296
|
}
|
298
297
|
}
|
@@ -307,7 +306,7 @@ const AuthenticationErrorName = "AuthenticationError";
|
|
307
306
|
*/
|
308
307
|
class AuthenticationError extends Error {
|
309
308
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
310
|
-
constructor(statusCode, errorBody) {
|
309
|
+
constructor(statusCode, errorBody, options) {
|
311
310
|
let errorResponse = {
|
312
311
|
error: "unknown",
|
313
312
|
errorDescription: "An unknown error occurred and no additional details are available.",
|
@@ -325,8 +324,8 @@ class AuthenticationError extends Error {
|
|
325
324
|
catch (e) {
|
326
325
|
if (statusCode === 400) {
|
327
326
|
errorResponse = {
|
328
|
-
error: "
|
329
|
-
errorDescription:
|
327
|
+
error: "invalid_request",
|
328
|
+
errorDescription: `The service indicated that the request was invalid.\n\n${errorBody}`,
|
330
329
|
};
|
331
330
|
}
|
332
331
|
else {
|
@@ -343,7 +342,9 @@ class AuthenticationError extends Error {
|
|
343
342
|
errorDescription: "An unknown error occurred and no additional details are available.",
|
344
343
|
};
|
345
344
|
}
|
346
|
-
super(`${errorResponse.error} Status code: ${statusCode}\nMore details:\n${errorResponse.errorDescription}
|
345
|
+
super(`${errorResponse.error} Status code: ${statusCode}\nMore details:\n${errorResponse.errorDescription},`,
|
346
|
+
// @ts-expect-error - TypeScript does not recognize this until we use ES2022 as the target; however, all our major runtimes do support the `cause` property
|
347
|
+
options);
|
347
348
|
this.statusCode = statusCode;
|
348
349
|
this.errorResponse = errorResponse;
|
349
350
|
// Ensure that this type reports the correct name
|
@@ -386,7 +387,9 @@ class AuthenticationRequiredError extends Error {
|
|
386
387
|
* 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.
|
387
388
|
*/
|
388
389
|
options) {
|
389
|
-
super(options.message
|
390
|
+
super(options.message,
|
391
|
+
// @ts-expect-error - TypeScript does not recognize this until we use ES2022 as the target; however, all our major runtimes do support the `cause` property
|
392
|
+
options.cause ? { cause: options.cause } : undefined);
|
390
393
|
this.scopes = options.scopes;
|
391
394
|
this.getTokenOptions = options.getTokenOptions;
|
392
395
|
this.name = "AuthenticationRequiredError";
|
@@ -497,8 +500,6 @@ const DefaultScopeSuffix = "/.default";
|
|
497
500
|
const imdsHost = "http://169.254.169.254";
|
498
501
|
const imdsEndpointPath = "/metadata/identity/oauth2/token";
|
499
502
|
const imdsApiVersion = "2018-02-01";
|
500
|
-
const azureArcAPIVersion = "2019-11-01";
|
501
|
-
const azureFabricVersion = "2019-07-01-preview";
|
502
503
|
|
503
504
|
// Copyright (c) Microsoft Corporation.
|
504
505
|
// Licensed under the MIT license.
|
@@ -590,14 +591,19 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
590
591
|
} }, options), { userAgentOptions: {
|
591
592
|
userAgentPrefix,
|
592
593
|
}, baseUri }));
|
594
|
+
this.allowInsecureConnection = false;
|
593
595
|
this.authorityHost = baseUri;
|
594
596
|
this.abortControllers = new Map();
|
595
597
|
this.allowLoggingAccountIdentifiers = (_b = options === null || options === void 0 ? void 0 : options.loggingOptions) === null || _b === void 0 ? void 0 : _b.allowLoggingAccountIdentifiers;
|
596
598
|
// used for WorkloadIdentity
|
597
599
|
this.tokenCredentialOptions = Object.assign({}, options);
|
600
|
+
// used for ManagedIdentity
|
601
|
+
if (options === null || options === void 0 ? void 0 : options.allowInsecureConnection) {
|
602
|
+
this.allowInsecureConnection = options.allowInsecureConnection;
|
603
|
+
}
|
598
604
|
}
|
599
605
|
async sendTokenRequest(request) {
|
600
|
-
logger$
|
606
|
+
logger$l.info(`IdentityClient: sending token request to [${request.url}]`);
|
601
607
|
const response = await this.sendRequest(request);
|
602
608
|
if (response.bodyAsText && (response.status === 200 || response.status === 201)) {
|
603
609
|
const parsedBody = JSON.parse(response.bodyAsText);
|
@@ -612,12 +618,12 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
612
618
|
},
|
613
619
|
refreshToken: parsedBody.refresh_token,
|
614
620
|
};
|
615
|
-
logger$
|
621
|
+
logger$l.info(`IdentityClient: [${request.url}] token acquired, expires on ${token.accessToken.expiresOnTimestamp}`);
|
616
622
|
return token;
|
617
623
|
}
|
618
624
|
else {
|
619
625
|
const error = new AuthenticationError(response.status, response.bodyAsText);
|
620
|
-
logger$
|
626
|
+
logger$l.warning(`IdentityClient: authentication error. HTTP status: ${response.status}, ${error.errorResponse.errorDescription}`);
|
621
627
|
throw error;
|
622
628
|
}
|
623
629
|
}
|
@@ -625,7 +631,7 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
625
631
|
if (refreshToken === undefined) {
|
626
632
|
return null;
|
627
633
|
}
|
628
|
-
logger$
|
634
|
+
logger$l.info(`IdentityClient: refreshing access token with client ID: ${clientId}, scopes: ${scopes} started`);
|
629
635
|
const refreshParams = {
|
630
636
|
grant_type: "refresh_token",
|
631
637
|
client_id: clientId,
|
@@ -651,7 +657,7 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
651
657
|
tracingOptions: updatedOptions.tracingOptions,
|
652
658
|
});
|
653
659
|
const response = await this.sendTokenRequest(request);
|
654
|
-
logger$
|
660
|
+
logger$l.info(`IdentityClient: refreshed token for client ID: ${clientId}`);
|
655
661
|
return response;
|
656
662
|
}
|
657
663
|
catch (err) {
|
@@ -660,11 +666,11 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
660
666
|
// It's likely that the refresh token has expired, so
|
661
667
|
// return null so that the credential implementation will
|
662
668
|
// initiate the authentication flow again.
|
663
|
-
logger$
|
669
|
+
logger$l.info(`IdentityClient: interaction required for client ID: ${clientId}`);
|
664
670
|
return null;
|
665
671
|
}
|
666
672
|
else {
|
667
|
-
logger$
|
673
|
+
logger$l.warning(`IdentityClient: failed refreshing token for client ID: ${clientId}: ${err}`);
|
668
674
|
throw err;
|
669
675
|
}
|
670
676
|
}
|
@@ -673,7 +679,7 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
673
679
|
// Here is a custom layer that allows us to abort requests that go through MSAL,
|
674
680
|
// since MSAL doesn't allow us to pass options all the way through.
|
675
681
|
generateAbortSignal(correlationId) {
|
676
|
-
const controller = new
|
682
|
+
const controller = new AbortController();
|
677
683
|
const controllers = this.abortControllers.get(correlationId) || [];
|
678
684
|
controllers.push(controller);
|
679
685
|
this.abortControllers.set(correlationId, controllers);
|
@@ -681,7 +687,7 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
681
687
|
controller.signal.onabort = (...params) => {
|
682
688
|
this.abortControllers.set(correlationId, undefined);
|
683
689
|
if (existingOnAbort) {
|
684
|
-
existingOnAbort(
|
690
|
+
existingOnAbort.apply(controller.signal, params);
|
685
691
|
}
|
686
692
|
};
|
687
693
|
return controller.signal;
|
@@ -712,6 +718,7 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
712
718
|
url,
|
713
719
|
method: "GET",
|
714
720
|
body: options === null || options === void 0 ? void 0 : options.body,
|
721
|
+
allowInsecureConnection: this.allowInsecureConnection,
|
715
722
|
headers: coreRestPipeline.createHttpHeaders(options === null || options === void 0 ? void 0 : options.headers),
|
716
723
|
abortSignal: this.generateAbortSignal(noCorrelationId),
|
717
724
|
});
|
@@ -729,6 +736,7 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
729
736
|
method: "POST",
|
730
737
|
body: options === null || options === void 0 ? void 0 : options.body,
|
731
738
|
headers: coreRestPipeline.createHttpHeaders(options === null || options === void 0 ? void 0 : options.headers),
|
739
|
+
allowInsecureConnection: this.allowInsecureConnection,
|
732
740
|
// MSAL doesn't send the correlation ID on the get requests.
|
733
741
|
abortSignal: this.generateAbortSignal(this.getCorrelationId(options)),
|
734
742
|
});
|
@@ -773,10 +781,10 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
773
781
|
}
|
774
782
|
const base64Metadata = accessToken.split(".")[1];
|
775
783
|
const { appid, upn, tid, oid } = JSON.parse(Buffer.from(base64Metadata, "base64").toString("utf8"));
|
776
|
-
logger$
|
784
|
+
logger$l.info(`[Authenticated account] Client ID: ${appid}. Tenant ID: ${tid}. User Principal Name: ${upn || unavailableUpn}. Object ID (user): ${oid}`);
|
777
785
|
}
|
778
786
|
catch (e) {
|
779
|
-
logger$
|
787
|
+
logger$l.warning("allowLoggingAccountIdentifiers was set, but we couldn't log the account information. Error:", e.message);
|
780
788
|
}
|
781
789
|
}
|
782
790
|
}
|
@@ -785,7 +793,7 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
785
793
|
// Licensed under the MIT license.
|
786
794
|
const CommonTenantId = "common";
|
787
795
|
const AzureAccountClientId = "aebc6443-996d-45c2-90f0-388ff96faa56"; // VSC: 'aebc6443-996d-45c2-90f0-388ff96faa56'
|
788
|
-
const logger$
|
796
|
+
const logger$k = credentialLogger("VisualStudioCodeCredential");
|
789
797
|
let findCredentials = undefined;
|
790
798
|
const vsCodeCredentialControl = {
|
791
799
|
setVsCodeCredentialFinder(finder) {
|
@@ -838,7 +846,7 @@ function getPropertyFromVSCode(property) {
|
|
838
846
|
}
|
839
847
|
}
|
840
848
|
catch (e) {
|
841
|
-
logger$
|
849
|
+
logger$k.info(`Failed to load the Visual Studio Code configuration file. Error: ${e.message}`);
|
842
850
|
return;
|
843
851
|
}
|
844
852
|
}
|
@@ -871,7 +879,7 @@ class VisualStudioCodeCredential {
|
|
871
879
|
const authorityHost = mapVSCodeAuthorityHosts[this.cloudName];
|
872
880
|
this.identityClient = new IdentityClient(Object.assign({ authorityHost }, options));
|
873
881
|
if (options && options.tenantId) {
|
874
|
-
checkTenantId(logger$
|
882
|
+
checkTenantId(logger$k, options.tenantId);
|
875
883
|
this.tenantId = options.tenantId;
|
876
884
|
}
|
877
885
|
else {
|
@@ -911,7 +919,7 @@ class VisualStudioCodeCredential {
|
|
911
919
|
async getToken(scopes, options) {
|
912
920
|
var _a, _b;
|
913
921
|
await this.prepareOnce();
|
914
|
-
const tenantId = processMultiTenantRequest(this.tenantId, options, this.additionallyAllowedTenantIds, logger$
|
922
|
+
const tenantId = processMultiTenantRequest(this.tenantId, options, this.additionallyAllowedTenantIds, logger$k) || this.tenantId;
|
915
923
|
if (findCredentials === undefined) {
|
916
924
|
throw new CredentialUnavailableError([
|
917
925
|
"No implementation of `VisualStudioCodeCredential` is available.",
|
@@ -925,7 +933,7 @@ class VisualStudioCodeCredential {
|
|
925
933
|
// Check to make sure the scope we get back is a valid scope
|
926
934
|
if (!scopeString.match(/^[0-9a-zA-Z-.:/]+$/)) {
|
927
935
|
const error = new Error("Invalid scope was specified by the user or calling client");
|
928
|
-
logger$
|
936
|
+
logger$k.getToken.info(formatError(scopes, error));
|
929
937
|
throw error;
|
930
938
|
}
|
931
939
|
if (scopeString.indexOf("offline_access") < 0) {
|
@@ -945,18 +953,18 @@ class VisualStudioCodeCredential {
|
|
945
953
|
if (refreshToken) {
|
946
954
|
const tokenResponse = await this.identityClient.refreshAccessToken(tenantId, AzureAccountClientId, scopeString, refreshToken, undefined);
|
947
955
|
if (tokenResponse) {
|
948
|
-
logger$
|
956
|
+
logger$k.getToken.info(formatSuccess(scopes));
|
949
957
|
return tokenResponse.accessToken;
|
950
958
|
}
|
951
959
|
else {
|
952
960
|
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/vscodecredential/troubleshoot.");
|
953
|
-
logger$
|
961
|
+
logger$k.getToken.info(formatError(scopes, error));
|
954
962
|
throw error;
|
955
963
|
}
|
956
964
|
}
|
957
965
|
else {
|
958
966
|
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/vscodecredential/troubleshoot.");
|
959
|
-
logger$
|
967
|
+
logger$k.getToken.info(formatError(scopes, error));
|
960
968
|
throw error;
|
961
969
|
}
|
962
970
|
}
|
@@ -1005,438 +1013,6 @@ function useIdentityPlugin(plugin) {
|
|
1005
1013
|
plugin(pluginContext);
|
1006
1014
|
}
|
1007
1015
|
|
1008
|
-
// Copyright (c) Microsoft Corporation.
|
1009
|
-
// Licensed under the MIT license.
|
1010
|
-
const msiName$6 = "ManagedIdentityCredential - CloudShellMSI";
|
1011
|
-
const logger$o = credentialLogger(msiName$6);
|
1012
|
-
/**
|
1013
|
-
* Generates the options used on the request for an access token.
|
1014
|
-
*/
|
1015
|
-
function prepareRequestOptions$5(scopes, clientId, resourceId) {
|
1016
|
-
const resource = mapScopesToResource(scopes);
|
1017
|
-
if (!resource) {
|
1018
|
-
throw new Error(`${msiName$6}: Multiple scopes are not supported.`);
|
1019
|
-
}
|
1020
|
-
const body = {
|
1021
|
-
resource,
|
1022
|
-
};
|
1023
|
-
if (clientId) {
|
1024
|
-
body.client_id = clientId;
|
1025
|
-
}
|
1026
|
-
if (resourceId) {
|
1027
|
-
body.msi_res_id = resourceId;
|
1028
|
-
}
|
1029
|
-
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
1030
|
-
if (!process.env.MSI_ENDPOINT) {
|
1031
|
-
throw new Error(`${msiName$6}: Missing environment variable: MSI_ENDPOINT`);
|
1032
|
-
}
|
1033
|
-
const params = new URLSearchParams(body);
|
1034
|
-
return {
|
1035
|
-
url: process.env.MSI_ENDPOINT,
|
1036
|
-
method: "POST",
|
1037
|
-
body: params.toString(),
|
1038
|
-
headers: coreRestPipeline.createHttpHeaders({
|
1039
|
-
Accept: "application/json",
|
1040
|
-
Metadata: "true",
|
1041
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
1042
|
-
}),
|
1043
|
-
};
|
1044
|
-
}
|
1045
|
-
/**
|
1046
|
-
* Defines how to determine whether the Azure Cloud Shell MSI is available, and also how to retrieve a token from the Azure Cloud Shell MSI.
|
1047
|
-
* Since Azure Managed Identities aren't available in the Azure Cloud Shell, we log a warning for users that try to access cloud shell using user assigned identity.
|
1048
|
-
*/
|
1049
|
-
const cloudShellMsi = {
|
1050
|
-
name: "cloudShellMsi",
|
1051
|
-
async isAvailable({ scopes }) {
|
1052
|
-
const resource = mapScopesToResource(scopes);
|
1053
|
-
if (!resource) {
|
1054
|
-
logger$o.info(`${msiName$6}: Unavailable. Multiple scopes are not supported.`);
|
1055
|
-
return false;
|
1056
|
-
}
|
1057
|
-
const result = Boolean(process.env.MSI_ENDPOINT);
|
1058
|
-
if (!result) {
|
1059
|
-
logger$o.info(`${msiName$6}: Unavailable. The environment variable MSI_ENDPOINT is needed.`);
|
1060
|
-
}
|
1061
|
-
return result;
|
1062
|
-
},
|
1063
|
-
async getToken(configuration, getTokenOptions = {}) {
|
1064
|
-
const { identityClient, scopes, clientId, resourceId } = configuration;
|
1065
|
-
if (clientId) {
|
1066
|
-
logger$o.warning(`${msiName$6}: user-assigned identities not supported. The argument clientId might be ignored by the service.`);
|
1067
|
-
}
|
1068
|
-
if (resourceId) {
|
1069
|
-
logger$o.warning(`${msiName$6}: user defined managed Identity by resource Id not supported. The argument resourceId might be ignored by the service.`);
|
1070
|
-
}
|
1071
|
-
logger$o.info(`${msiName$6}: Using the endpoint coming form the environment variable MSI_ENDPOINT = ${process.env.MSI_ENDPOINT}.`);
|
1072
|
-
const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$5(scopes, clientId, resourceId)), {
|
1073
|
-
// Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
|
1074
|
-
allowInsecureConnection: true }));
|
1075
|
-
const tokenResponse = await identityClient.sendTokenRequest(request);
|
1076
|
-
return (tokenResponse && tokenResponse.accessToken) || null;
|
1077
|
-
},
|
1078
|
-
};
|
1079
|
-
|
1080
|
-
// Copyright (c) Microsoft Corporation.
|
1081
|
-
// Licensed under the MIT license.
|
1082
|
-
const msiName$5 = "ManagedIdentityCredential - AppServiceMSI 2017";
|
1083
|
-
const logger$n = credentialLogger(msiName$5);
|
1084
|
-
/**
|
1085
|
-
* Generates the options used on the request for an access token.
|
1086
|
-
*/
|
1087
|
-
function prepareRequestOptions$4(scopes, clientId) {
|
1088
|
-
const resource = mapScopesToResource(scopes);
|
1089
|
-
if (!resource) {
|
1090
|
-
throw new Error(`${msiName$5}: Multiple scopes are not supported.`);
|
1091
|
-
}
|
1092
|
-
const queryParameters = {
|
1093
|
-
resource,
|
1094
|
-
"api-version": "2017-09-01",
|
1095
|
-
};
|
1096
|
-
if (clientId) {
|
1097
|
-
queryParameters.clientid = clientId;
|
1098
|
-
}
|
1099
|
-
const query = new URLSearchParams(queryParameters);
|
1100
|
-
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
1101
|
-
if (!process.env.MSI_ENDPOINT) {
|
1102
|
-
throw new Error(`${msiName$5}: Missing environment variable: MSI_ENDPOINT`);
|
1103
|
-
}
|
1104
|
-
if (!process.env.MSI_SECRET) {
|
1105
|
-
throw new Error(`${msiName$5}: Missing environment variable: MSI_SECRET`);
|
1106
|
-
}
|
1107
|
-
return {
|
1108
|
-
url: `${process.env.MSI_ENDPOINT}?${query.toString()}`,
|
1109
|
-
method: "GET",
|
1110
|
-
headers: coreRestPipeline.createHttpHeaders({
|
1111
|
-
Accept: "application/json",
|
1112
|
-
secret: process.env.MSI_SECRET,
|
1113
|
-
}),
|
1114
|
-
};
|
1115
|
-
}
|
1116
|
-
/**
|
1117
|
-
* Defines how to determine whether the Azure App Service MSI is available, and also how to retrieve a token from the Azure App Service MSI.
|
1118
|
-
*/
|
1119
|
-
const appServiceMsi2017 = {
|
1120
|
-
name: "appServiceMsi2017",
|
1121
|
-
async isAvailable({ scopes }) {
|
1122
|
-
const resource = mapScopesToResource(scopes);
|
1123
|
-
if (!resource) {
|
1124
|
-
logger$n.info(`${msiName$5}: Unavailable. Multiple scopes are not supported.`);
|
1125
|
-
return false;
|
1126
|
-
}
|
1127
|
-
const env = process.env;
|
1128
|
-
const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);
|
1129
|
-
if (!result) {
|
1130
|
-
logger$n.info(`${msiName$5}: Unavailable. The environment variables needed are: MSI_ENDPOINT and MSI_SECRET.`);
|
1131
|
-
}
|
1132
|
-
return result;
|
1133
|
-
},
|
1134
|
-
async getToken(configuration, getTokenOptions = {}) {
|
1135
|
-
const { identityClient, scopes, clientId, resourceId } = configuration;
|
1136
|
-
if (resourceId) {
|
1137
|
-
logger$n.warning(`${msiName$5}: managed Identity by resource Id is not supported. Argument resourceId might be ignored by the service.`);
|
1138
|
-
}
|
1139
|
-
logger$n.info(`${msiName$5}: Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`);
|
1140
|
-
const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$4(scopes, clientId)), {
|
1141
|
-
// Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
|
1142
|
-
allowInsecureConnection: true }));
|
1143
|
-
const tokenResponse = await identityClient.sendTokenRequest(request);
|
1144
|
-
return (tokenResponse && tokenResponse.accessToken) || null;
|
1145
|
-
},
|
1146
|
-
};
|
1147
|
-
|
1148
|
-
// Copyright (c) Microsoft Corporation.
|
1149
|
-
// Licensed under the MIT license.
|
1150
|
-
const msiName$4 = "ManagedIdentityCredential - AppServiceMSI 2019";
|
1151
|
-
const logger$m = credentialLogger(msiName$4);
|
1152
|
-
/**
|
1153
|
-
* Generates the options used on the request for an access token.
|
1154
|
-
*/
|
1155
|
-
function prepareRequestOptions$3(scopes, clientId, resourceId) {
|
1156
|
-
const resource = mapScopesToResource(scopes);
|
1157
|
-
if (!resource) {
|
1158
|
-
throw new Error(`${msiName$4}: Multiple scopes are not supported.`);
|
1159
|
-
}
|
1160
|
-
const queryParameters = {
|
1161
|
-
resource,
|
1162
|
-
"api-version": "2019-08-01",
|
1163
|
-
};
|
1164
|
-
if (clientId) {
|
1165
|
-
queryParameters.client_id = clientId;
|
1166
|
-
}
|
1167
|
-
if (resourceId) {
|
1168
|
-
queryParameters.mi_res_id = resourceId;
|
1169
|
-
}
|
1170
|
-
const query = new URLSearchParams(queryParameters);
|
1171
|
-
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
1172
|
-
if (!process.env.IDENTITY_ENDPOINT) {
|
1173
|
-
throw new Error(`${msiName$4}: Missing environment variable: IDENTITY_ENDPOINT`);
|
1174
|
-
}
|
1175
|
-
if (!process.env.IDENTITY_HEADER) {
|
1176
|
-
throw new Error(`${msiName$4}: Missing environment variable: IDENTITY_HEADER`);
|
1177
|
-
}
|
1178
|
-
return {
|
1179
|
-
url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,
|
1180
|
-
method: "GET",
|
1181
|
-
headers: coreRestPipeline.createHttpHeaders({
|
1182
|
-
Accept: "application/json",
|
1183
|
-
"X-IDENTITY-HEADER": process.env.IDENTITY_HEADER,
|
1184
|
-
}),
|
1185
|
-
};
|
1186
|
-
}
|
1187
|
-
/**
|
1188
|
-
* Defines how to determine whether the Azure App Service MSI is available, and also how to retrieve a token from the Azure App Service MSI.
|
1189
|
-
*/
|
1190
|
-
const appServiceMsi2019 = {
|
1191
|
-
name: "appServiceMsi2019",
|
1192
|
-
async isAvailable({ scopes }) {
|
1193
|
-
const resource = mapScopesToResource(scopes);
|
1194
|
-
if (!resource) {
|
1195
|
-
logger$m.info(`${msiName$4}: Unavailable. Multiple scopes are not supported.`);
|
1196
|
-
return false;
|
1197
|
-
}
|
1198
|
-
const env = process.env;
|
1199
|
-
const result = Boolean(env.IDENTITY_ENDPOINT && env.IDENTITY_HEADER);
|
1200
|
-
if (!result) {
|
1201
|
-
logger$m.info(`${msiName$4}: Unavailable. The environment variables needed are: IDENTITY_ENDPOINT and IDENTITY_HEADER.`);
|
1202
|
-
}
|
1203
|
-
return result;
|
1204
|
-
},
|
1205
|
-
async getToken(configuration, getTokenOptions = {}) {
|
1206
|
-
const { identityClient, scopes, clientId, resourceId } = configuration;
|
1207
|
-
logger$m.info(`${msiName$4}: Using the endpoint and the secret coming form the environment variables: IDENTITY_ENDPOINT=${process.env.IDENTITY_ENDPOINT} and IDENTITY_HEADER=[REDACTED].`);
|
1208
|
-
const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$3(scopes, clientId, resourceId)), {
|
1209
|
-
// Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
|
1210
|
-
allowInsecureConnection: true }));
|
1211
|
-
const tokenResponse = await identityClient.sendTokenRequest(request);
|
1212
|
-
return (tokenResponse && tokenResponse.accessToken) || null;
|
1213
|
-
},
|
1214
|
-
};
|
1215
|
-
|
1216
|
-
// Copyright (c) Microsoft Corporation.
|
1217
|
-
// Licensed under the MIT license.
|
1218
|
-
const msiName$3 = "ManagedIdentityCredential - Azure Arc MSI";
|
1219
|
-
const logger$l = credentialLogger(msiName$3);
|
1220
|
-
/**
|
1221
|
-
* Generates the options used on the request for an access token.
|
1222
|
-
*/
|
1223
|
-
function prepareRequestOptions$2(scopes, clientId, resourceId) {
|
1224
|
-
const resource = mapScopesToResource(scopes);
|
1225
|
-
if (!resource) {
|
1226
|
-
throw new Error(`${msiName$3}: Multiple scopes are not supported.`);
|
1227
|
-
}
|
1228
|
-
const queryParameters = {
|
1229
|
-
resource,
|
1230
|
-
"api-version": azureArcAPIVersion,
|
1231
|
-
};
|
1232
|
-
if (clientId) {
|
1233
|
-
queryParameters.client_id = clientId;
|
1234
|
-
}
|
1235
|
-
if (resourceId) {
|
1236
|
-
queryParameters.msi_res_id = resourceId;
|
1237
|
-
}
|
1238
|
-
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
1239
|
-
if (!process.env.IDENTITY_ENDPOINT) {
|
1240
|
-
throw new Error(`${msiName$3}: Missing environment variable: IDENTITY_ENDPOINT`);
|
1241
|
-
}
|
1242
|
-
const query = new URLSearchParams(queryParameters);
|
1243
|
-
return coreRestPipeline.createPipelineRequest({
|
1244
|
-
// Should be similar to: http://localhost:40342/metadata/identity/oauth2/token
|
1245
|
-
url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,
|
1246
|
-
method: "GET",
|
1247
|
-
headers: coreRestPipeline.createHttpHeaders({
|
1248
|
-
Accept: "application/json",
|
1249
|
-
Metadata: "true",
|
1250
|
-
}),
|
1251
|
-
});
|
1252
|
-
}
|
1253
|
-
/**
|
1254
|
-
* Does a request to the authentication provider that results in a file path.
|
1255
|
-
*/
|
1256
|
-
async function filePathRequest(identityClient, requestPrepareOptions) {
|
1257
|
-
const response = await identityClient.sendRequest(coreRestPipeline.createPipelineRequest(requestPrepareOptions));
|
1258
|
-
if (response.status !== 401) {
|
1259
|
-
let message = "";
|
1260
|
-
if (response.bodyAsText) {
|
1261
|
-
message = ` Response: ${response.bodyAsText}`;
|
1262
|
-
}
|
1263
|
-
throw new AuthenticationError(response.status, `${msiName$3}: To authenticate with Azure Arc MSI, status code 401 is expected on the first request. ${message}`);
|
1264
|
-
}
|
1265
|
-
const authHeader = response.headers.get("www-authenticate") || "";
|
1266
|
-
try {
|
1267
|
-
return authHeader.split("=").slice(1)[0];
|
1268
|
-
}
|
1269
|
-
catch (e) {
|
1270
|
-
throw Error(`Invalid www-authenticate header format: ${authHeader}`);
|
1271
|
-
}
|
1272
|
-
}
|
1273
|
-
function platformToFilePath() {
|
1274
|
-
switch (process.platform) {
|
1275
|
-
case "win32":
|
1276
|
-
if (!process.env.PROGRAMDATA) {
|
1277
|
-
throw new Error(`${msiName$3}: PROGRAMDATA environment variable has no value.`);
|
1278
|
-
}
|
1279
|
-
return `${process.env.PROGRAMDATA}\\AzureConnectedMachineAgent\\Tokens`;
|
1280
|
-
case "linux":
|
1281
|
-
return "/var/opt/azcmagent/tokens";
|
1282
|
-
default:
|
1283
|
-
throw new Error(`${msiName$3}: Unsupported platform ${process.platform}.`);
|
1284
|
-
}
|
1285
|
-
}
|
1286
|
-
/**
|
1287
|
-
* Validates that a given Azure Arc MSI file path is valid for use.
|
1288
|
-
*
|
1289
|
-
* A valid file will:
|
1290
|
-
* 1. Be in the expected path for the current platform.
|
1291
|
-
* 2. Have a `.key` extension.
|
1292
|
-
* 3. Be at most 4096 bytes in size.
|
1293
|
-
*/
|
1294
|
-
function validateKeyFile(filePath) {
|
1295
|
-
if (!filePath) {
|
1296
|
-
throw new Error(`${msiName$3}: Failed to find the token file.`);
|
1297
|
-
}
|
1298
|
-
if (!filePath.endsWith(".key")) {
|
1299
|
-
throw new Error(`${msiName$3}: unexpected file path from HIMDS service: ${filePath}.`);
|
1300
|
-
}
|
1301
|
-
const expectedPath = platformToFilePath();
|
1302
|
-
if (!filePath.startsWith(expectedPath)) {
|
1303
|
-
throw new Error(`${msiName$3}: unexpected file path from HIMDS service: ${filePath}.`);
|
1304
|
-
}
|
1305
|
-
const stats = fs$1.statSync(filePath);
|
1306
|
-
if (stats.size > 4096) {
|
1307
|
-
throw new Error(`${msiName$3}: The file at ${filePath} is larger than expected at ${stats.size} bytes.`);
|
1308
|
-
}
|
1309
|
-
}
|
1310
|
-
/**
|
1311
|
-
* Defines how to determine whether the Azure Arc MSI is available, and also how to retrieve a token from the Azure Arc MSI.
|
1312
|
-
*/
|
1313
|
-
const arcMsi = {
|
1314
|
-
name: "arc",
|
1315
|
-
async isAvailable({ scopes }) {
|
1316
|
-
const resource = mapScopesToResource(scopes);
|
1317
|
-
if (!resource) {
|
1318
|
-
logger$l.info(`${msiName$3}: Unavailable. Multiple scopes are not supported.`);
|
1319
|
-
return false;
|
1320
|
-
}
|
1321
|
-
const result = Boolean(process.env.IMDS_ENDPOINT && process.env.IDENTITY_ENDPOINT);
|
1322
|
-
if (!result) {
|
1323
|
-
logger$l.info(`${msiName$3}: The environment variables needed are: IMDS_ENDPOINT and IDENTITY_ENDPOINT`);
|
1324
|
-
}
|
1325
|
-
return result;
|
1326
|
-
},
|
1327
|
-
async getToken(configuration, getTokenOptions = {}) {
|
1328
|
-
var _a;
|
1329
|
-
const { identityClient, scopes, clientId, resourceId } = configuration;
|
1330
|
-
if (clientId) {
|
1331
|
-
logger$l.warning(`${msiName$3}: user-assigned identities not supported. The argument clientId might be ignored by the service.`);
|
1332
|
-
}
|
1333
|
-
if (resourceId) {
|
1334
|
-
logger$l.warning(`${msiName$3}: user defined managed Identity by resource Id is not supported. Argument resourceId will be ignored.`);
|
1335
|
-
}
|
1336
|
-
logger$l.info(`${msiName$3}: Authenticating.`);
|
1337
|
-
const requestOptions = Object.assign(Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$2(scopes, clientId, resourceId)), { allowInsecureConnection: true });
|
1338
|
-
const filePath = await filePathRequest(identityClient, requestOptions);
|
1339
|
-
validateKeyFile(filePath);
|
1340
|
-
const key = await fs$1.promises.readFile(filePath, { encoding: "utf-8" });
|
1341
|
-
(_a = requestOptions.headers) === null || _a === void 0 ? void 0 : _a.set("Authorization", `Basic ${key}`);
|
1342
|
-
const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({}, requestOptions), {
|
1343
|
-
// Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
|
1344
|
-
allowInsecureConnection: true }));
|
1345
|
-
const tokenResponse = await identityClient.sendTokenRequest(request);
|
1346
|
-
return (tokenResponse && tokenResponse.accessToken) || null;
|
1347
|
-
},
|
1348
|
-
};
|
1349
|
-
|
1350
|
-
// Copyright (c) Microsoft Corporation.
|
1351
|
-
// Licensed under the MIT license.
|
1352
|
-
// This MSI can be easily tested by deploying a container to Azure Service Fabric with the Dockerfile:
|
1353
|
-
//
|
1354
|
-
// FROM node:12
|
1355
|
-
// RUN wget https://host.any/path/bash.sh
|
1356
|
-
// CMD ["bash", "bash.sh"]
|
1357
|
-
//
|
1358
|
-
// Where the bash script contains:
|
1359
|
-
//
|
1360
|
-
// curl --insecure $IDENTITY_ENDPOINT'?api-version=2019-07-01-preview&resource=https://vault.azure.net/' -H "Secret: $IDENTITY_HEADER"
|
1361
|
-
//
|
1362
|
-
const msiName$2 = "ManagedIdentityCredential - Fabric MSI";
|
1363
|
-
const logger$k = credentialLogger(msiName$2);
|
1364
|
-
/**
|
1365
|
-
* Generates the options used on the request for an access token.
|
1366
|
-
*/
|
1367
|
-
function prepareRequestOptions$1(scopes, clientId, resourceId) {
|
1368
|
-
const resource = mapScopesToResource(scopes);
|
1369
|
-
if (!resource) {
|
1370
|
-
throw new Error(`${msiName$2}: Multiple scopes are not supported.`);
|
1371
|
-
}
|
1372
|
-
const queryParameters = {
|
1373
|
-
resource,
|
1374
|
-
"api-version": azureFabricVersion,
|
1375
|
-
};
|
1376
|
-
if (clientId) {
|
1377
|
-
queryParameters.client_id = clientId;
|
1378
|
-
}
|
1379
|
-
if (resourceId) {
|
1380
|
-
queryParameters.msi_res_id = resourceId;
|
1381
|
-
}
|
1382
|
-
const query = new URLSearchParams(queryParameters);
|
1383
|
-
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
1384
|
-
if (!process.env.IDENTITY_ENDPOINT) {
|
1385
|
-
throw new Error("Missing environment variable: IDENTITY_ENDPOINT");
|
1386
|
-
}
|
1387
|
-
if (!process.env.IDENTITY_HEADER) {
|
1388
|
-
throw new Error("Missing environment variable: IDENTITY_HEADER");
|
1389
|
-
}
|
1390
|
-
return {
|
1391
|
-
url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,
|
1392
|
-
method: "GET",
|
1393
|
-
headers: coreRestPipeline.createHttpHeaders({
|
1394
|
-
Accept: "application/json",
|
1395
|
-
secret: process.env.IDENTITY_HEADER,
|
1396
|
-
}),
|
1397
|
-
};
|
1398
|
-
}
|
1399
|
-
/**
|
1400
|
-
* Defines how to determine whether the Azure Service Fabric MSI is available, and also how to retrieve a token from the Azure Service Fabric MSI.
|
1401
|
-
*/
|
1402
|
-
const fabricMsi = {
|
1403
|
-
name: "fabricMsi",
|
1404
|
-
async isAvailable({ scopes }) {
|
1405
|
-
const resource = mapScopesToResource(scopes);
|
1406
|
-
if (!resource) {
|
1407
|
-
logger$k.info(`${msiName$2}: Unavailable. Multiple scopes are not supported.`);
|
1408
|
-
return false;
|
1409
|
-
}
|
1410
|
-
const env = process.env;
|
1411
|
-
const result = Boolean(env.IDENTITY_ENDPOINT && env.IDENTITY_HEADER && env.IDENTITY_SERVER_THUMBPRINT);
|
1412
|
-
if (!result) {
|
1413
|
-
logger$k.info(`${msiName$2}: Unavailable. The environment variables needed are: IDENTITY_ENDPOINT, IDENTITY_HEADER and IDENTITY_SERVER_THUMBPRINT`);
|
1414
|
-
}
|
1415
|
-
return result;
|
1416
|
-
},
|
1417
|
-
async getToken(configuration, getTokenOptions = {}) {
|
1418
|
-
const { scopes, identityClient, clientId, resourceId } = configuration;
|
1419
|
-
if (resourceId) {
|
1420
|
-
logger$k.warning(`${msiName$2}: user defined managed Identity by resource Id is not supported. Argument resourceId might be ignored by the service.`);
|
1421
|
-
}
|
1422
|
-
logger$k.info([
|
1423
|
-
`${msiName$2}:`,
|
1424
|
-
"Using the endpoint and the secret coming from the environment variables:",
|
1425
|
-
`IDENTITY_ENDPOINT=${process.env.IDENTITY_ENDPOINT},`,
|
1426
|
-
"IDENTITY_HEADER=[REDACTED] and",
|
1427
|
-
"IDENTITY_SERVER_THUMBPRINT=[REDACTED].",
|
1428
|
-
].join(" "));
|
1429
|
-
const request = coreRestPipeline.createPipelineRequest(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$1(scopes, clientId, resourceId)));
|
1430
|
-
request.agent = new https.Agent({
|
1431
|
-
// This is necessary because Service Fabric provides a self-signed certificate.
|
1432
|
-
// The alternative path is to verify the certificate using the IDENTITY_SERVER_THUMBPRINT env variable.
|
1433
|
-
rejectUnauthorized: false,
|
1434
|
-
});
|
1435
|
-
const tokenResponse = await identityClient.sendTokenRequest(request);
|
1436
|
-
return (tokenResponse && tokenResponse.accessToken) || null;
|
1437
|
-
},
|
1438
|
-
};
|
1439
|
-
|
1440
1016
|
// Copyright (c) Microsoft Corporation.
|
1441
1017
|
// Licensed under the MIT license.
|
1442
1018
|
/**
|
@@ -1776,6 +1352,41 @@ const imdsMsi = {
|
|
1776
1352
|
},
|
1777
1353
|
};
|
1778
1354
|
|
1355
|
+
// Copyright (c) Microsoft Corporation.
|
1356
|
+
// Licensed under the MIT license.
|
1357
|
+
// Matches the default retry configuration in expontentialRetryStrategy.ts
|
1358
|
+
const DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 64;
|
1359
|
+
/**
|
1360
|
+
* An additional policy that retries on 404 errors. The default retry policy does not retry on
|
1361
|
+
* 404s, but the IMDS endpoint can return 404s when the token is not yet available. This policy
|
1362
|
+
* will retry on 404s with an exponential backoff.
|
1363
|
+
*
|
1364
|
+
* @param msiRetryConfig - The retry configuration for the MSI credential.
|
1365
|
+
* @returns - The policy that will retry on 404s.
|
1366
|
+
*/
|
1367
|
+
function imdsRetryPolicy(msiRetryConfig) {
|
1368
|
+
return coreRestPipeline.retryPolicy([
|
1369
|
+
{
|
1370
|
+
name: "imdsRetryPolicy",
|
1371
|
+
retry: ({ retryCount, response }) => {
|
1372
|
+
if ((response === null || response === void 0 ? void 0 : response.status) !== 404) {
|
1373
|
+
return { skipStrategy: true };
|
1374
|
+
}
|
1375
|
+
// Exponentially increase the delay each time
|
1376
|
+
const exponentialDelay = msiRetryConfig.startDelayInMs * Math.pow(2, retryCount);
|
1377
|
+
// Don't let the delay exceed the maximum
|
1378
|
+
const clampedExponentialDelay = Math.min(DEFAULT_CLIENT_MAX_RETRY_INTERVAL, exponentialDelay);
|
1379
|
+
// Allow the final value to have some "jitter" (within 50% of the delay size) so
|
1380
|
+
// that retries across multiple clients don't occur simultaneously.
|
1381
|
+
const retryAfterInMs = clampedExponentialDelay / 2 + coreUtil.getRandomIntegerInclusive(0, clampedExponentialDelay / 2);
|
1382
|
+
return { retryAfterInMs };
|
1383
|
+
},
|
1384
|
+
},
|
1385
|
+
], {
|
1386
|
+
maxRetries: msiRetryConfig.maxRetries,
|
1387
|
+
});
|
1388
|
+
}
|
1389
|
+
|
1779
1390
|
// Copyright (c) Microsoft Corporation.
|
1780
1391
|
// Licensed under the MIT license.
|
1781
1392
|
/**
|
@@ -1918,6 +1529,10 @@ function calculateRegionalAuthority(regionalAuthority) {
|
|
1918
1529
|
|
1919
1530
|
// Copyright (c) Microsoft Corporation.
|
1920
1531
|
// Licensed under the MIT license.
|
1532
|
+
/**
|
1533
|
+
* The default logger used if no logger was passed in by the credential.
|
1534
|
+
*/
|
1535
|
+
const msalLogger = credentialLogger("MsalClient");
|
1921
1536
|
/**
|
1922
1537
|
* A call to open(), but mockable
|
1923
1538
|
* @internal
|
@@ -1925,13 +1540,6 @@ function calculateRegionalAuthority(regionalAuthority) {
|
|
1925
1540
|
const interactiveBrowserMockable = {
|
1926
1541
|
open,
|
1927
1542
|
};
|
1928
|
-
|
1929
|
-
// Copyright (c) Microsoft Corporation.
|
1930
|
-
// Licensed under the MIT license.
|
1931
|
-
/**
|
1932
|
-
* The default logger used if no logger was passed in by the credential.
|
1933
|
-
*/
|
1934
|
-
const msalLogger = credentialLogger("MsalClient");
|
1935
1543
|
/**
|
1936
1544
|
* Generates the configuration for MSAL (Microsoft Authentication Library).
|
1937
1545
|
*
|
@@ -1956,7 +1564,7 @@ function generateMsalConfiguration(clientId, tenantId, msalClientOptions = {}) {
|
|
1956
1564
|
networkClient: httpClient,
|
1957
1565
|
loggerOptions: {
|
1958
1566
|
loggerCallback: defaultLoggerCallback((_c = msalClientOptions.logger) !== null && _c !== void 0 ? _c : msalLogger),
|
1959
|
-
logLevel: getMSALLogLevel(logger$
|
1567
|
+
logLevel: getMSALLogLevel(logger$m.getLogLevel()),
|
1960
1568
|
piiLoggingEnabled: (_d = msalClientOptions.loggingOptions) === null || _d === void 0 ? void 0 : _d.enableUnsafeSupportLogging,
|
1961
1569
|
},
|
1962
1570
|
},
|
@@ -2377,8 +1985,14 @@ class ClientAssertionCredential {
|
|
2377
1985
|
* @param options - Options for configuring the client which makes the authentication request.
|
2378
1986
|
*/
|
2379
1987
|
constructor(tenantId, clientId, getAssertion, options = {}) {
|
2380
|
-
if (!tenantId
|
2381
|
-
throw new
|
1988
|
+
if (!tenantId) {
|
1989
|
+
throw new CredentialUnavailableError("ClientAssertionCredential: tenantId is a required parameter.");
|
1990
|
+
}
|
1991
|
+
if (!clientId) {
|
1992
|
+
throw new CredentialUnavailableError("ClientAssertionCredential: clientId is a required parameter.");
|
1993
|
+
}
|
1994
|
+
if (!getAssertion) {
|
1995
|
+
throw new CredentialUnavailableError("ClientAssertionCredential: clientAssertion is a required parameter.");
|
2382
1996
|
}
|
2383
1997
|
this.tenantId = tenantId;
|
2384
1998
|
this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(options === null || options === void 0 ? void 0 : options.additionallyAllowedTenants);
|
@@ -2453,10 +2067,20 @@ class WorkloadIdentityCredential {
|
|
2453
2067
|
if (tenantId) {
|
2454
2068
|
checkTenantId(logger$g, tenantId);
|
2455
2069
|
}
|
2456
|
-
if (clientId
|
2457
|
-
|
2458
|
-
|
2070
|
+
if (!clientId) {
|
2071
|
+
throw new CredentialUnavailableError(`${credentialName$4}: is unavailable. clientId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_CLIENT_ID".
|
2072
|
+
See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
|
2073
|
+
}
|
2074
|
+
if (!tenantId) {
|
2075
|
+
throw new CredentialUnavailableError(`${credentialName$4}: is unavailable. tenantId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_TENANT_ID".
|
2076
|
+
See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
|
2459
2077
|
}
|
2078
|
+
if (!this.federatedTokenFilePath) {
|
2079
|
+
throw new CredentialUnavailableError(`${credentialName$4}: is unavailable. federatedTokenFilePath is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_FEDERATED_TOKEN_FILE".
|
2080
|
+
See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
|
2081
|
+
}
|
2082
|
+
logger$g.info(`Invoking ClientAssertionCredential with tenant ID: ${tenantId}, clientId: ${workloadIdentityCredentialOptions.clientId} and federated token path: [REDACTED]`);
|
2083
|
+
this.client = new ClientAssertionCredential(tenantId, clientId, this.readFileContents.bind(this), options);
|
2460
2084
|
}
|
2461
2085
|
/**
|
2462
2086
|
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
@@ -2472,7 +2096,7 @@ class WorkloadIdentityCredential {
|
|
2472
2096
|
In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables -
|
2473
2097
|
"AZURE_TENANT_ID",
|
2474
2098
|
"AZURE_CLIENT_ID",
|
2475
|
-
"AZURE_FEDERATED_TOKEN_FILE". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot
|
2099
|
+
"AZURE_FEDERATED_TOKEN_FILE". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`;
|
2476
2100
|
logger$g.info(errorMessage);
|
2477
2101
|
throw new CredentialUnavailableError(errorMessage);
|
2478
2102
|
}
|
@@ -2509,132 +2133,76 @@ const logger$f = credentialLogger(msiName);
|
|
2509
2133
|
/**
|
2510
2134
|
* Defines how to determine whether the token exchange MSI is available, and also how to retrieve a token from the token exchange MSI.
|
2511
2135
|
*/
|
2512
|
-
|
2513
|
-
|
2514
|
-
|
2515
|
-
|
2516
|
-
|
2517
|
-
|
2518
|
-
|
2519
|
-
|
2520
|
-
|
2521
|
-
|
2522
|
-
|
2523
|
-
|
2524
|
-
|
2525
|
-
|
2526
|
-
|
2527
|
-
|
2528
|
-
|
2529
|
-
|
2530
|
-
|
2531
|
-
},
|
2532
|
-
};
|
2533
|
-
}
|
2136
|
+
const tokenExchangeMsi = {
|
2137
|
+
name: "tokenExchangeMsi",
|
2138
|
+
async isAvailable({ clientId }) {
|
2139
|
+
const env = process.env;
|
2140
|
+
const result = Boolean((clientId || env.AZURE_CLIENT_ID) &&
|
2141
|
+
env.AZURE_TENANT_ID &&
|
2142
|
+
process.env.AZURE_FEDERATED_TOKEN_FILE);
|
2143
|
+
if (!result) {
|
2144
|
+
logger$f.info(`${msiName}: 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`);
|
2145
|
+
}
|
2146
|
+
return result;
|
2147
|
+
},
|
2148
|
+
async getToken(configuration, getTokenOptions = {}) {
|
2149
|
+
const { scopes, clientId } = configuration;
|
2150
|
+
const identityClientTokenCredentialOptions = {};
|
2151
|
+
const workloadIdentityCredential = new WorkloadIdentityCredential(Object.assign(Object.assign({ clientId, tenantId: process.env.AZURE_TENANT_ID, tokenFilePath: process.env.AZURE_FEDERATED_TOKEN_FILE }, identityClientTokenCredentialOptions), { disableInstanceDiscovery: true }));
|
2152
|
+
return workloadIdentityCredential.getToken(scopes, getTokenOptions);
|
2153
|
+
},
|
2154
|
+
};
|
2534
2155
|
|
2535
2156
|
// Copyright (c) Microsoft Corporation.
|
2536
2157
|
// Licensed under the MIT license.
|
2537
|
-
const logger$e = credentialLogger("ManagedIdentityCredential");
|
2538
|
-
class
|
2539
|
-
constructor(clientIdOrOptions, options) {
|
2158
|
+
const logger$e = credentialLogger("ManagedIdentityCredential(MSAL)");
|
2159
|
+
class MsalMsiProvider {
|
2160
|
+
constructor(clientIdOrOptions, options = {}) {
|
2540
2161
|
var _a, _b;
|
2541
|
-
this.isEndpointUnavailable = null;
|
2542
|
-
this.isAppTokenProviderInitialized = false;
|
2543
2162
|
this.msiRetryConfig = {
|
2544
2163
|
maxRetries: 5,
|
2545
2164
|
startDelayInMs: 800,
|
2546
2165
|
intervalIncrement: 2,
|
2547
2166
|
};
|
2548
|
-
let _options;
|
2167
|
+
let _options = {};
|
2549
2168
|
if (typeof clientIdOrOptions === "string") {
|
2550
2169
|
this.clientId = clientIdOrOptions;
|
2551
2170
|
_options = options;
|
2552
2171
|
}
|
2553
2172
|
else {
|
2554
2173
|
this.clientId = clientIdOrOptions === null || clientIdOrOptions === void 0 ? void 0 : clientIdOrOptions.clientId;
|
2555
|
-
_options = clientIdOrOptions;
|
2174
|
+
_options = clientIdOrOptions !== null && clientIdOrOptions !== void 0 ? clientIdOrOptions : {};
|
2556
2175
|
}
|
2557
2176
|
this.resourceId = _options === null || _options === void 0 ? void 0 : _options.resourceId;
|
2558
2177
|
// For JavaScript users.
|
2559
2178
|
if (this.clientId && this.resourceId) {
|
2560
2179
|
throw new Error(`ManagedIdentityCredential - Client Id and Resource Id can't be provided at the same time.`);
|
2561
2180
|
}
|
2181
|
+
// ManagedIdentity uses http for local requests
|
2182
|
+
_options.allowInsecureConnection = true;
|
2562
2183
|
if (((_a = _options === null || _options === void 0 ? void 0 : _options.retryOptions) === null || _a === void 0 ? void 0 : _a.maxRetries) !== undefined) {
|
2563
2184
|
this.msiRetryConfig.maxRetries = _options.retryOptions.maxRetries;
|
2564
2185
|
}
|
2565
|
-
this.identityClient = new IdentityClient(_options);
|
2566
|
-
this.
|
2567
|
-
|
2568
|
-
|
2569
|
-
|
2570
|
-
* since this wasn't done previously before adding token cache support
|
2571
|
-
*/
|
2572
|
-
this.confidentialApp = new msalCommon.ConfidentialClientApplication({
|
2573
|
-
auth: {
|
2574
|
-
authority: "https://login.microsoftonline.com/managed_identity",
|
2575
|
-
clientId: (_b = this.clientId) !== null && _b !== void 0 ? _b : DeveloperSignOnClientId,
|
2576
|
-
clientSecret: "dummy-secret",
|
2577
|
-
cloudDiscoveryMetadata: '{"tenant_discovery_endpoint":"https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}',
|
2578
|
-
authorityMetadata: '{"token_endpoint":"https://login.microsoftonline.com/common/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/common/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/{tenantid}/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/common/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/common/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/common/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/common/kerberos","tenant_region_scope":null,"cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}',
|
2579
|
-
clientCapabilities: [],
|
2186
|
+
this.identityClient = new IdentityClient(Object.assign(Object.assign({}, _options), { additionalPolicies: [{ policy: imdsRetryPolicy(this.msiRetryConfig), position: "perCall" }] }));
|
2187
|
+
this.managedIdentityApp = new msalCommon.ManagedIdentityApplication({
|
2188
|
+
managedIdentityIdParams: {
|
2189
|
+
userAssignedClientId: this.clientId,
|
2190
|
+
userAssignedResourceId: this.resourceId,
|
2580
2191
|
},
|
2581
2192
|
system: {
|
2193
|
+
// todo: proxyUrl?
|
2194
|
+
disableInternalRetries: true,
|
2195
|
+
networkClient: this.identityClient,
|
2582
2196
|
loggerOptions: {
|
2583
|
-
logLevel: getMSALLogLevel(logger$
|
2197
|
+
logLevel: getMSALLogLevel(logger$m.getLogLevel()),
|
2198
|
+
piiLoggingEnabled: (_b = options.loggingOptions) === null || _b === void 0 ? void 0 : _b.enableUnsafeSupportLogging,
|
2199
|
+
loggerCallback: defaultLoggerCallback(logger$e),
|
2584
2200
|
},
|
2585
2201
|
},
|
2586
2202
|
});
|
2587
|
-
|
2588
|
-
|
2589
|
-
|
2590
|
-
return this.cachedMSI;
|
2591
|
-
}
|
2592
|
-
const MSIs = [
|
2593
|
-
arcMsi,
|
2594
|
-
fabricMsi,
|
2595
|
-
appServiceMsi2019,
|
2596
|
-
appServiceMsi2017,
|
2597
|
-
cloudShellMsi,
|
2598
|
-
tokenExchangeMsi(),
|
2599
|
-
imdsMsi,
|
2600
|
-
];
|
2601
|
-
for (const msi of MSIs) {
|
2602
|
-
if (await msi.isAvailable({
|
2603
|
-
scopes,
|
2604
|
-
identityClient: this.isAvailableIdentityClient,
|
2605
|
-
clientId: this.clientId,
|
2606
|
-
resourceId: this.resourceId,
|
2607
|
-
getTokenOptions,
|
2608
|
-
})) {
|
2609
|
-
this.cachedMSI = msi;
|
2610
|
-
return msi;
|
2611
|
-
}
|
2612
|
-
}
|
2613
|
-
throw new CredentialUnavailableError(`ManagedIdentityCredential - No MSI credential available`);
|
2614
|
-
}
|
2615
|
-
async authenticateManagedIdentity(scopes, getTokenOptions) {
|
2616
|
-
const { span, updatedOptions } = tracingClient.startSpan(`ManagedIdentityCredential.authenticateManagedIdentity`, getTokenOptions);
|
2617
|
-
try {
|
2618
|
-
// Determining the available MSI, and avoiding checking for other MSIs while the program is running.
|
2619
|
-
const availableMSI = await this.cachedAvailableMSI(scopes, updatedOptions);
|
2620
|
-
return availableMSI.getToken({
|
2621
|
-
identityClient: this.identityClient,
|
2622
|
-
scopes,
|
2623
|
-
clientId: this.clientId,
|
2624
|
-
resourceId: this.resourceId,
|
2625
|
-
retryConfig: this.msiRetryConfig,
|
2626
|
-
}, updatedOptions);
|
2627
|
-
}
|
2628
|
-
catch (err) {
|
2629
|
-
span.setStatus({
|
2630
|
-
status: "error",
|
2631
|
-
error: err,
|
2632
|
-
});
|
2633
|
-
throw err;
|
2634
|
-
}
|
2635
|
-
finally {
|
2636
|
-
span.end();
|
2637
|
-
}
|
2203
|
+
this.isAvailableIdentityClient = new IdentityClient(Object.assign(Object.assign({}, _options), { retryOptions: {
|
2204
|
+
maxRetries: 0,
|
2205
|
+
} }));
|
2638
2206
|
}
|
2639
2207
|
/**
|
2640
2208
|
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
@@ -2645,133 +2213,93 @@ class LegacyMsiProvider {
|
|
2645
2213
|
* @param options - The options used to configure any requests this
|
2646
2214
|
* TokenCredential implementation might make.
|
2647
2215
|
*/
|
2648
|
-
async getToken(scopes, options) {
|
2649
|
-
|
2650
|
-
const
|
2651
|
-
|
2652
|
-
|
2653
|
-
|
2654
|
-
|
2655
|
-
|
2656
|
-
const
|
2657
|
-
|
2658
|
-
|
2659
|
-
|
2660
|
-
|
2661
|
-
|
2662
|
-
|
2663
|
-
|
2664
|
-
|
2665
|
-
|
2666
|
-
|
2667
|
-
|
2668
|
-
|
2669
|
-
|
2670
|
-
|
2216
|
+
async getToken(scopes, options = {}) {
|
2217
|
+
logger$e.getToken.info("Using the MSAL provider for Managed Identity.");
|
2218
|
+
const resource = mapScopesToResource(scopes);
|
2219
|
+
if (!resource) {
|
2220
|
+
throw new CredentialUnavailableError(`ManagedIdentityCredential: Multiple scopes are not supported. Scopes: ${JSON.stringify(scopes)}`);
|
2221
|
+
}
|
2222
|
+
return tracingClient.withSpan("ManagedIdentityCredential.getToken", options, async () => {
|
2223
|
+
try {
|
2224
|
+
const isTokenExchangeMsi = await tokenExchangeMsi.isAvailable({
|
2225
|
+
scopes,
|
2226
|
+
clientId: this.clientId,
|
2227
|
+
getTokenOptions: options,
|
2228
|
+
identityClient: this.identityClient,
|
2229
|
+
resourceId: this.resourceId,
|
2230
|
+
});
|
2231
|
+
// Most scenarios are handled by MSAL except for two:
|
2232
|
+
// AKS pod identity - MSAL does not implement the token exchange flow.
|
2233
|
+
// IMDS Endpoint probing - MSAL does not do any probing before trying to get a token.
|
2234
|
+
// As a DefaultAzureCredential optimization we probe the IMDS endpoint with a short timeout and no retries before actually trying to get a token
|
2235
|
+
// We will continue to implement these features in the Identity library.
|
2236
|
+
const identitySource = this.managedIdentityApp.getManagedIdentitySource();
|
2237
|
+
const isImdsMsi = identitySource === "DefaultToImds" || identitySource === "Imds"; // Neither actually checks that IMDS endpoint is available, just that it's the source the MSAL _would_ try to use.
|
2238
|
+
logger$e.getToken.info(`MSAL Identity source: ${identitySource}`);
|
2239
|
+
if (isTokenExchangeMsi) {
|
2240
|
+
// In the AKS scenario we will use the existing tokenExchangeMsi indefinitely.
|
2241
|
+
logger$e.getToken.info("Using the token exchange managed identity.");
|
2242
|
+
const result = await tokenExchangeMsi.getToken({
|
2243
|
+
scopes,
|
2244
|
+
clientId: this.clientId,
|
2245
|
+
identityClient: this.identityClient,
|
2246
|
+
retryConfig: this.msiRetryConfig,
|
2247
|
+
resourceId: this.resourceId,
|
2248
|
+
});
|
2249
|
+
if (result === null) {
|
2250
|
+
throw new CredentialUnavailableError("Attempted to use the token exchange managed identity, but received a null response.");
|
2251
|
+
}
|
2252
|
+
return result;
|
2671
2253
|
}
|
2672
|
-
if (
|
2673
|
-
//
|
2674
|
-
//
|
2675
|
-
|
2676
|
-
|
2677
|
-
|
2678
|
-
|
2679
|
-
|
2680
|
-
|
2681
|
-
|
2254
|
+
else if (isImdsMsi) {
|
2255
|
+
// In the IMDS scenario we will probe the IMDS endpoint to ensure it's available before trying to get a token.
|
2256
|
+
// If the IMDS endpoint is not available and this is the source that MSAL will use, we will fail-fast with an error that tells DAC to move to the next credential.
|
2257
|
+
logger$e.getToken.info("Using the IMDS endpoint to probe for availability.");
|
2258
|
+
const isAvailable = await imdsMsi.isAvailable({
|
2259
|
+
scopes,
|
2260
|
+
clientId: this.clientId,
|
2261
|
+
getTokenOptions: options,
|
2262
|
+
identityClient: this.isAvailableIdentityClient,
|
2263
|
+
resourceId: this.resourceId,
|
2264
|
+
});
|
2265
|
+
if (!isAvailable) {
|
2266
|
+
throw new CredentialUnavailableError(`ManagedIdentityCredential: Attempted to use the IMDS endpoint, but it is not available.`);
|
2267
|
+
}
|
2682
2268
|
}
|
2683
|
-
//
|
2684
|
-
//
|
2685
|
-
//
|
2686
|
-
|
2687
|
-
|
2688
|
-
|
2689
|
-
|
2690
|
-
|
2691
|
-
|
2692
|
-
logger$e.getToken.info(
|
2693
|
-
|
2694
|
-
|
2695
|
-
|
2696
|
-
|
2697
|
-
}
|
2698
|
-
catch (err) {
|
2699
|
-
// CredentialUnavailable errors are expected to reach here.
|
2700
|
-
// We intend them to bubble up, so that DefaultAzureCredential can catch them.
|
2701
|
-
if (err.name === "AuthenticationRequiredError") {
|
2702
|
-
throw err;
|
2703
|
-
}
|
2704
|
-
// Expected errors to reach this point:
|
2705
|
-
// - Errors coming from a method unexpectedly breaking.
|
2706
|
-
// - When identityClient.sendTokenRequest throws, in which case
|
2707
|
-
// if the status code was 400, it means that the endpoint is working,
|
2708
|
-
// but no identity is available.
|
2709
|
-
span.setStatus({
|
2710
|
-
status: "error",
|
2711
|
-
error: err,
|
2712
|
-
});
|
2713
|
-
// If either the network is unreachable,
|
2714
|
-
// we can safely assume the credential is unavailable.
|
2715
|
-
if (err.code === "ENETUNREACH") {
|
2716
|
-
const error = new CredentialUnavailableError(`ManagedIdentityCredential: Unavailable. Network unreachable. Message: ${err.message}`);
|
2717
|
-
logger$e.getToken.info(formatError(scopes, error));
|
2718
|
-
throw error;
|
2719
|
-
}
|
2720
|
-
// If either the host was unreachable,
|
2721
|
-
// we can safely assume the credential is unavailable.
|
2722
|
-
if (err.code === "EHOSTUNREACH") {
|
2723
|
-
const error = new CredentialUnavailableError(`ManagedIdentityCredential: Unavailable. No managed identity endpoint found. Message: ${err.message}`);
|
2724
|
-
logger$e.getToken.info(formatError(scopes, error));
|
2725
|
-
throw error;
|
2726
|
-
}
|
2727
|
-
// If err.statusCode has a value of 400, it comes from sendTokenRequest,
|
2728
|
-
// and it means that the endpoint is working, but that no identity is available.
|
2729
|
-
if (err.statusCode === 400) {
|
2730
|
-
throw new CredentialUnavailableError(`ManagedIdentityCredential: The managed identity endpoint is indicating there's no available identity. Message: ${err.message}`);
|
2269
|
+
// If we got this far, it means:
|
2270
|
+
// - This is not a tokenExchangeMsi,
|
2271
|
+
// - We already probed for IMDS endpoint availability and failed-fast if it's unreachable.
|
2272
|
+
// We can proceed normally by calling MSAL for a token.
|
2273
|
+
logger$e.getToken.info("Calling into MSAL for managed identity token.");
|
2274
|
+
const token = await this.managedIdentityApp.acquireToken({
|
2275
|
+
resource,
|
2276
|
+
});
|
2277
|
+
this.ensureValidMsalToken(scopes, token, options);
|
2278
|
+
logger$e.getToken.info(formatSuccess(scopes));
|
2279
|
+
return {
|
2280
|
+
expiresOnTimestamp: token.expiresOn.getTime(),
|
2281
|
+
token: token.accessToken,
|
2282
|
+
};
|
2731
2283
|
}
|
2732
|
-
|
2733
|
-
|
2734
|
-
|
2735
|
-
|
2736
|
-
|
2737
|
-
|
2738
|
-
throw error;
|
2284
|
+
catch (err) {
|
2285
|
+
logger$e.getToken.error(formatError(scopes, err));
|
2286
|
+
// AuthenticationRequiredError described as Error to enforce authentication after trying to retrieve a token silently.
|
2287
|
+
// TODO: why would this _ever_ happen considering we're not trying the silent request in this flow?
|
2288
|
+
if (err.name === "AuthenticationRequiredError") {
|
2289
|
+
throw err;
|
2739
2290
|
}
|
2291
|
+
if (isNetworkError(err)) {
|
2292
|
+
throw new CredentialUnavailableError(`ManagedIdentityCredential: Network unreachable. Message: ${err.message}`, { cause: err });
|
2293
|
+
}
|
2294
|
+
throw new CredentialUnavailableError(`ManagedIdentityCredential: Authentication failed. Message ${err.message}`, { cause: err });
|
2740
2295
|
}
|
2741
|
-
|
2742
|
-
// This will throw silently during any ChainedTokenCredential.
|
2743
|
-
if (err.statusCode === undefined) {
|
2744
|
-
throw new CredentialUnavailableError(`ManagedIdentityCredential: Authentication failed. Message ${err.message}`);
|
2745
|
-
}
|
2746
|
-
// Any other error should break the chain.
|
2747
|
-
throw new AuthenticationError(err.statusCode, {
|
2748
|
-
error: `ManagedIdentityCredential authentication failed.`,
|
2749
|
-
error_description: err.message,
|
2750
|
-
});
|
2751
|
-
}
|
2752
|
-
finally {
|
2753
|
-
// Finally is always called, both if we return and if we throw in the above try/catch.
|
2754
|
-
span.end();
|
2755
|
-
}
|
2756
|
-
}
|
2757
|
-
/**
|
2758
|
-
* Handles the MSAL authentication result.
|
2759
|
-
* If the result has an account, we update the local account reference.
|
2760
|
-
* If the token received is invalid, an error will be thrown depending on what's missing.
|
2761
|
-
*/
|
2762
|
-
handleResult(scopes, result, getTokenOptions) {
|
2763
|
-
this.ensureValidMsalToken(scopes, result, getTokenOptions);
|
2764
|
-
logger$e.getToken.info(formatSuccess(scopes));
|
2765
|
-
return {
|
2766
|
-
token: result.accessToken,
|
2767
|
-
expiresOnTimestamp: result.expiresOn.getTime(),
|
2768
|
-
};
|
2296
|
+
});
|
2769
2297
|
}
|
2770
2298
|
/**
|
2771
2299
|
* Ensures the validity of the MSAL token
|
2772
2300
|
*/
|
2773
2301
|
ensureValidMsalToken(scopes, msalToken, getTokenOptions) {
|
2774
|
-
const
|
2302
|
+
const createError = (message) => {
|
2775
2303
|
logger$e.getToken.info(message);
|
2776
2304
|
return new AuthenticationRequiredError({
|
2777
2305
|
scopes: Array.isArray(scopes) ? scopes : [scopes],
|
@@ -2780,43 +2308,33 @@ class LegacyMsiProvider {
|
|
2780
2308
|
});
|
2781
2309
|
};
|
2782
2310
|
if (!msalToken) {
|
2783
|
-
throw
|
2311
|
+
throw createError("No response.");
|
2784
2312
|
}
|
2785
2313
|
if (!msalToken.expiresOn) {
|
2786
|
-
throw
|
2314
|
+
throw createError(`Response had no "expiresOn" property.`);
|
2787
2315
|
}
|
2788
2316
|
if (!msalToken.accessToken) {
|
2789
|
-
throw
|
2790
|
-
}
|
2791
|
-
}
|
2792
|
-
|
2793
|
-
|
2794
|
-
|
2795
|
-
|
2796
|
-
|
2797
|
-
|
2798
|
-
|
2799
|
-
|
2800
|
-
|
2801
|
-
|
2802
|
-
|
2803
|
-
|
2804
|
-
|
2805
|
-
|
2806
|
-
|
2807
|
-
};
|
2808
|
-
}
|
2809
|
-
else {
|
2810
|
-
logger$e.info(`SetAppTokenProvider token has "no_access_token_returned" as the saved token`);
|
2811
|
-
return {
|
2812
|
-
accessToken: "no_access_token_returned",
|
2813
|
-
expiresInSeconds: 0,
|
2814
|
-
};
|
2815
|
-
}
|
2816
|
-
});
|
2817
|
-
this.isAppTokenProviderInitialized = true;
|
2317
|
+
throw createError(`Response had no "accessToken" property.`);
|
2318
|
+
}
|
2319
|
+
}
|
2320
|
+
}
|
2321
|
+
function isNetworkError(err) {
|
2322
|
+
// MSAL error
|
2323
|
+
if (err.errorCode === "network_error") {
|
2324
|
+
return true;
|
2325
|
+
}
|
2326
|
+
// Probe errors
|
2327
|
+
if (err.code === "ENETUNREACH" || err.code === "EHOSTUNREACH") {
|
2328
|
+
return true;
|
2329
|
+
}
|
2330
|
+
// This is a special case for Docker Desktop which responds with a 403 with a message that contains "A socket operation was attempted to an unreachable network" or "A socket operation was attempted to an unreachable host"
|
2331
|
+
// rather than just timing out, as expected.
|
2332
|
+
if (err.statusCode === 403 || err.code === 403) {
|
2333
|
+
if (err.message.includes("unreachable")) {
|
2334
|
+
return true;
|
2818
2335
|
}
|
2819
2336
|
}
|
2337
|
+
return false;
|
2820
2338
|
}
|
2821
2339
|
|
2822
2340
|
// Copyright (c) Microsoft Corporation.
|
@@ -2835,7 +2353,11 @@ class ManagedIdentityCredential {
|
|
2835
2353
|
* @hidden
|
2836
2354
|
*/
|
2837
2355
|
constructor(clientIdOrOptions, options) {
|
2838
|
-
|
2356
|
+
// https://github.com/Azure/azure-sdk-for-js/issues/30189
|
2357
|
+
// If needed, you may release a hotfix to quickly rollback to the legacy implementation by changing the following line to:
|
2358
|
+
// this.implProvider = new LegacyMsiProvider(clientIdOrOptions, options);
|
2359
|
+
// Once stabilized, you can remove the legacy implementation and inline the msalMsiProvider code here as a drop-in replacement.
|
2360
|
+
this.implProvider = new MsalMsiProvider(clientIdOrOptions, options);
|
2839
2361
|
}
|
2840
2362
|
/**
|
2841
2363
|
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
@@ -3345,33 +2867,45 @@ class AzurePowerShellCredential {
|
|
3345
2867
|
commandStack.shift();
|
3346
2868
|
continue;
|
3347
2869
|
}
|
3348
|
-
let tenantSection = "";
|
3349
|
-
if (tenantId) {
|
3350
|
-
tenantSection = `-TenantId "${tenantId}"`;
|
3351
|
-
}
|
3352
2870
|
const results = await runCommands([
|
3353
2871
|
[
|
3354
2872
|
powerShellCommand,
|
3355
2873
|
"-NoProfile",
|
3356
2874
|
"-NonInteractive",
|
3357
2875
|
"-Command",
|
3358
|
-
|
3359
|
-
|
3360
|
-
|
3361
|
-
|
3362
|
-
|
3363
|
-
|
3364
|
-
|
3365
|
-
|
2876
|
+
`
|
2877
|
+
$tenantId = "${tenantId !== null && tenantId !== void 0 ? tenantId : ""}"
|
2878
|
+
$m = Import-Module Az.Accounts -MinimumVersion 2.2.0 -PassThru
|
2879
|
+
$useSecureString = $m.Version -ge [version]'2.17.0'
|
2880
|
+
|
2881
|
+
$params = @{
|
2882
|
+
ResourceUrl = "${resource}"
|
2883
|
+
}
|
2884
|
+
|
2885
|
+
if ($tenantId.Length -gt 0) {
|
2886
|
+
$params["TenantId"] = $tenantId
|
2887
|
+
}
|
2888
|
+
|
2889
|
+
if ($useSecureString) {
|
2890
|
+
$params["AsSecureString"] = $true
|
2891
|
+
}
|
2892
|
+
|
2893
|
+
$token = Get-AzAccessToken @params
|
2894
|
+
|
2895
|
+
$result = New-Object -TypeName PSObject
|
2896
|
+
$result | Add-Member -MemberType NoteProperty -Name ExpiresOn -Value $token.ExpiresOn
|
2897
|
+
if ($useSecureString) {
|
2898
|
+
$result | Add-Member -MemberType NoteProperty -Name Token -Value (ConvertFrom-SecureString -AsPlainText $token.Token)
|
2899
|
+
} else {
|
2900
|
+
$result | Add-Member -MemberType NoteProperty -Name Token -Value $token.Token
|
2901
|
+
}
|
2902
|
+
|
2903
|
+
Write-Output (ConvertTo-Json $result)
|
2904
|
+
`,
|
3366
2905
|
],
|
3367
2906
|
]);
|
3368
|
-
const result = results[
|
3369
|
-
|
3370
|
-
return JSON.parse(result);
|
3371
|
-
}
|
3372
|
-
catch (e) {
|
3373
|
-
throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);
|
3374
|
-
}
|
2907
|
+
const result = results[0];
|
2908
|
+
return parseJsonToken(result);
|
3375
2909
|
}
|
3376
2910
|
throw new Error(`Unable to execute PowerShell. Ensure that it is installed in your system`);
|
3377
2911
|
}
|
@@ -3418,6 +2952,38 @@ class AzurePowerShellCredential {
|
|
3418
2952
|
});
|
3419
2953
|
}
|
3420
2954
|
}
|
2955
|
+
/**
|
2956
|
+
*
|
2957
|
+
* @internal
|
2958
|
+
*/
|
2959
|
+
async function parseJsonToken(result) {
|
2960
|
+
const jsonRegex = /{[^{}]*}/g;
|
2961
|
+
const matches = result.match(jsonRegex);
|
2962
|
+
let resultWithoutToken = result;
|
2963
|
+
if (matches) {
|
2964
|
+
try {
|
2965
|
+
for (const item of matches) {
|
2966
|
+
try {
|
2967
|
+
const jsonContent = JSON.parse(item);
|
2968
|
+
if (jsonContent === null || jsonContent === void 0 ? void 0 : jsonContent.Token) {
|
2969
|
+
resultWithoutToken = resultWithoutToken.replace(item, "");
|
2970
|
+
if (resultWithoutToken) {
|
2971
|
+
logger$b.getToken.warning(resultWithoutToken);
|
2972
|
+
}
|
2973
|
+
return jsonContent;
|
2974
|
+
}
|
2975
|
+
}
|
2976
|
+
catch (e) {
|
2977
|
+
continue;
|
2978
|
+
}
|
2979
|
+
}
|
2980
|
+
}
|
2981
|
+
catch (e) {
|
2982
|
+
throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);
|
2983
|
+
}
|
2984
|
+
}
|
2985
|
+
throw new Error(`No access token found in the output. Received output: ${result}`);
|
2986
|
+
}
|
3421
2987
|
|
3422
2988
|
// Copyright (c) Microsoft Corporation.
|
3423
2989
|
// Licensed under the MIT license.
|
@@ -3550,7 +3116,8 @@ class ClientCertificateCredential {
|
|
3550
3116
|
});
|
3551
3117
|
}
|
3552
3118
|
async buildClientCertificate() {
|
3553
|
-
|
3119
|
+
var _a;
|
3120
|
+
const parts = await parseCertificate(this.certificateConfiguration, (_a = this.sendCertificateChain) !== null && _a !== void 0 ? _a : false);
|
3554
3121
|
let privateKey;
|
3555
3122
|
if (this.certificateConfiguration.certificatePassword !== undefined) {
|
3556
3123
|
privateKey = crypto.createPrivateKey({
|
@@ -3573,34 +3140,41 @@ class ClientCertificateCredential {
|
|
3573
3140
|
x5c: parts.x5c,
|
3574
3141
|
};
|
3575
3142
|
}
|
3576
|
-
|
3577
|
-
|
3578
|
-
|
3579
|
-
|
3580
|
-
|
3581
|
-
|
3582
|
-
|
3583
|
-
|
3584
|
-
|
3585
|
-
|
3586
|
-
|
3587
|
-
|
3588
|
-
|
3589
|
-
|
3590
|
-
|
3591
|
-
|
3592
|
-
|
3593
|
-
|
3594
|
-
|
3595
|
-
|
3596
|
-
.
|
3597
|
-
|
3598
|
-
|
3599
|
-
|
3600
|
-
|
3601
|
-
|
3602
|
-
|
3603
|
-
|
3143
|
+
}
|
3144
|
+
/**
|
3145
|
+
* Parses a certificate into its relevant parts
|
3146
|
+
*
|
3147
|
+
* @param certificateConfiguration - The certificate contents or path to the certificate
|
3148
|
+
* @param sendCertificateChain - true if the entire certificate chain should be sent for SNI, false otherwise
|
3149
|
+
* @returns The parsed certificate parts and the certificate contents
|
3150
|
+
*/
|
3151
|
+
async function parseCertificate(certificateConfiguration, sendCertificateChain) {
|
3152
|
+
const certificate = certificateConfiguration.certificate;
|
3153
|
+
const certificatePath = certificateConfiguration.certificatePath;
|
3154
|
+
const certificateContents = certificate || (await promises.readFile(certificatePath, "utf8"));
|
3155
|
+
const x5c = sendCertificateChain ? certificateContents : undefined;
|
3156
|
+
const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
|
3157
|
+
const publicKeys = [];
|
3158
|
+
// Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
|
3159
|
+
let match;
|
3160
|
+
do {
|
3161
|
+
match = certificatePattern.exec(certificateContents);
|
3162
|
+
if (match) {
|
3163
|
+
publicKeys.push(match[3]);
|
3164
|
+
}
|
3165
|
+
} while (match);
|
3166
|
+
if (publicKeys.length === 0) {
|
3167
|
+
throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
|
3168
|
+
}
|
3169
|
+
const thumbprint = crypto.createHash("sha1")
|
3170
|
+
.update(Buffer.from(publicKeys[0], "base64"))
|
3171
|
+
.digest("hex")
|
3172
|
+
.toUpperCase();
|
3173
|
+
return {
|
3174
|
+
certificateContents,
|
3175
|
+
thumbprint,
|
3176
|
+
x5c,
|
3177
|
+
};
|
3604
3178
|
}
|
3605
3179
|
|
3606
3180
|
// Copyright (c) Microsoft Corporation.
|
@@ -3626,8 +3200,14 @@ class ClientSecretCredential {
|
|
3626
3200
|
* @param options - Options for configuring the client which makes the authentication request.
|
3627
3201
|
*/
|
3628
3202
|
constructor(tenantId, clientId, clientSecret, options = {}) {
|
3629
|
-
if (!tenantId
|
3630
|
-
throw new
|
3203
|
+
if (!tenantId) {
|
3204
|
+
throw new CredentialUnavailableError("ClientSecretCredential: tenantId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.");
|
3205
|
+
}
|
3206
|
+
if (!clientId) {
|
3207
|
+
throw new CredentialUnavailableError("ClientSecretCredential: clientId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.");
|
3208
|
+
}
|
3209
|
+
if (!clientSecret) {
|
3210
|
+
throw new CredentialUnavailableError("ClientSecretCredential: clientSecret is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.");
|
3631
3211
|
}
|
3632
3212
|
this.clientSecret = clientSecret;
|
3633
3213
|
this.tenantId = tenantId;
|
@@ -3673,8 +3253,17 @@ class UsernamePasswordCredential {
|
|
3673
3253
|
* @param options - Options for configuring the client which makes the authentication request.
|
3674
3254
|
*/
|
3675
3255
|
constructor(tenantId, clientId, username, password, options = {}) {
|
3676
|
-
if (!tenantId
|
3677
|
-
throw new
|
3256
|
+
if (!tenantId) {
|
3257
|
+
throw new CredentialUnavailableError("UsernamePasswordCredential: tenantId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
|
3258
|
+
}
|
3259
|
+
if (!clientId) {
|
3260
|
+
throw new CredentialUnavailableError("UsernamePasswordCredential: clientId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
|
3261
|
+
}
|
3262
|
+
if (!username) {
|
3263
|
+
throw new CredentialUnavailableError("UsernamePasswordCredential: username is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
|
3264
|
+
}
|
3265
|
+
if (!password) {
|
3266
|
+
throw new CredentialUnavailableError("UsernamePasswordCredential: password is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
|
3678
3267
|
}
|
3679
3268
|
this.tenantId = tenantId;
|
3680
3269
|
this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(options === null || options === void 0 ? void 0 : options.additionallyAllowedTenants);
|
@@ -3721,6 +3310,7 @@ const AllSupportedEnvironmentVariables = [
|
|
3721
3310
|
"AZURE_USERNAME",
|
3722
3311
|
"AZURE_PASSWORD",
|
3723
3312
|
"AZURE_ADDITIONALLY_ALLOWED_TENANTS",
|
3313
|
+
"AZURE_CLIENT_SEND_CERTIFICATE_CHAIN",
|
3724
3314
|
];
|
3725
3315
|
function getAdditionallyAllowedTenants() {
|
3726
3316
|
var _a;
|
@@ -3729,6 +3319,13 @@ function getAdditionallyAllowedTenants() {
|
|
3729
3319
|
}
|
3730
3320
|
const credentialName$2 = "EnvironmentCredential";
|
3731
3321
|
const logger$6 = credentialLogger(credentialName$2);
|
3322
|
+
function getSendCertificateChain() {
|
3323
|
+
var _a;
|
3324
|
+
const sendCertificateChain = ((_a = process.env.AZURE_CLIENT_SEND_CERTIFICATE_CHAIN) !== null && _a !== void 0 ? _a : "").toLowerCase();
|
3325
|
+
const result = sendCertificateChain === "true" || sendCertificateChain === "1";
|
3326
|
+
logger$6.verbose(`AZURE_CLIENT_SEND_CERTIFICATE_CHAIN: ${process.env.AZURE_CLIENT_SEND_CERTIFICATE_CHAIN}; sendCertificateChain: ${result}`);
|
3327
|
+
return result;
|
3328
|
+
}
|
3732
3329
|
/**
|
3733
3330
|
* Enables authentication to Microsoft Entra ID using a client secret or certificate, or as a user
|
3734
3331
|
* with a username and password.
|
@@ -3748,6 +3345,7 @@ class EnvironmentCredential {
|
|
3748
3345
|
* - `AZURE_CLIENT_SECRET`: A client secret that was generated for the App Registration.
|
3749
3346
|
* - `AZURE_CLIENT_CERTIFICATE_PATH`: The path to a PEM certificate to use during the authentication, instead of the client secret.
|
3750
3347
|
* - `AZURE_CLIENT_CERTIFICATE_PASSWORD`: (optional) password for the certificate file.
|
3348
|
+
* - `AZURE_CLIENT_SEND_CERTIFICATE_CHAIN`: (optional) indicates that the certificate chain should be set in x5c header to support subject name / issuer based authentication.
|
3751
3349
|
*
|
3752
3350
|
* Alternatively, users can provide environment variables for username and password authentication:
|
3753
3351
|
* - `AZURE_USERNAME`: Username to authenticate with.
|
@@ -3765,7 +3363,8 @@ class EnvironmentCredential {
|
|
3765
3363
|
logger$6.info(`Found the following environment variables: ${assigned}`);
|
3766
3364
|
const tenantId = process.env.AZURE_TENANT_ID, clientId = process.env.AZURE_CLIENT_ID, clientSecret = process.env.AZURE_CLIENT_SECRET;
|
3767
3365
|
const additionallyAllowedTenantIds = getAdditionallyAllowedTenants();
|
3768
|
-
const
|
3366
|
+
const sendCertificateChain = getSendCertificateChain();
|
3367
|
+
const newOptions = Object.assign(Object.assign({}, options), { additionallyAllowedTenantIds, sendCertificateChain });
|
3769
3368
|
if (tenantId) {
|
3770
3369
|
checkTenantId(logger$6, tenantId);
|
3771
3370
|
}
|
@@ -4026,7 +3625,7 @@ class InteractiveBrowserCredential {
|
|
4026
3625
|
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
4027
3626
|
* If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
|
4028
3627
|
*
|
4029
|
-
* If the token can't be retrieved silently, this method will
|
3628
|
+
* If the token can't be retrieved silently, this method will always generate a challenge for the user.
|
4030
3629
|
*
|
4031
3630
|
* On Node.js, this credential has [Proof Key for Code Exchange (PKCE)](https://datatracker.ietf.org/doc/html/rfc7636) enabled by default.
|
4032
3631
|
* PKCE is a security feature that mitigates authentication code interception attacks.
|
@@ -4112,7 +3711,7 @@ class DeviceCodeCredential {
|
|
4112
3711
|
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
4113
3712
|
* If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
|
4114
3713
|
*
|
4115
|
-
* If the token can't be retrieved silently, this method will
|
3714
|
+
* If the token can't be retrieved silently, this method will always generate a challenge for the user.
|
4116
3715
|
*
|
4117
3716
|
* @param scopes - The list of scopes for which the token will have access.
|
4118
3717
|
* @param options - The options used to configure any requests this
|
@@ -4146,8 +3745,17 @@ class AzurePipelinesCredential {
|
|
4146
3745
|
* @param options - The identity client options to use for authentication.
|
4147
3746
|
*/
|
4148
3747
|
constructor(tenantId, clientId, serviceConnectionId, systemAccessToken, options) {
|
4149
|
-
if (!clientId
|
4150
|
-
throw new CredentialUnavailableError(`${credentialName$1}: is unavailable.
|
3748
|
+
if (!clientId) {
|
3749
|
+
throw new CredentialUnavailableError(`${credentialName$1}: is unavailable. clientId is a required parameter.`);
|
3750
|
+
}
|
3751
|
+
if (!tenantId) {
|
3752
|
+
throw new CredentialUnavailableError(`${credentialName$1}: is unavailable. tenantId is a required parameter.`);
|
3753
|
+
}
|
3754
|
+
if (!serviceConnectionId) {
|
3755
|
+
throw new CredentialUnavailableError(`${credentialName$1}: is unavailable. serviceConnectionId is a required parameter.`);
|
3756
|
+
}
|
3757
|
+
if (!systemAccessToken) {
|
3758
|
+
throw new CredentialUnavailableError(`${credentialName$1}: is unavailable. systemAccessToken is a required parameter.`);
|
4151
3759
|
}
|
4152
3760
|
this.identityClient = new IdentityClient(options);
|
4153
3761
|
checkTenantId(logger$2, tenantId);
|
@@ -4200,31 +3808,46 @@ class AzurePipelinesCredential {
|
|
4200
3808
|
}),
|
4201
3809
|
});
|
4202
3810
|
const response = await this.identityClient.sendRequest(request);
|
4203
|
-
|
4204
|
-
|
4205
|
-
|
4206
|
-
|
3811
|
+
return handleOidcResponse(response);
|
3812
|
+
}
|
3813
|
+
}
|
3814
|
+
function handleOidcResponse(response) {
|
3815
|
+
const text = response.bodyAsText;
|
3816
|
+
if (!text) {
|
3817
|
+
logger$2.error(`${credentialName$1}: Authentication Failed. Received null token from OIDC request. Response status- ${response.status}. Complete response - ${JSON.stringify(response)}`);
|
3818
|
+
throw new AuthenticationError(response.status, {
|
3819
|
+
error: `${credentialName$1}: Authentication Failed. Received null token from OIDC request.`,
|
3820
|
+
error_description: `${JSON.stringify(response)}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`,
|
3821
|
+
});
|
3822
|
+
}
|
3823
|
+
try {
|
3824
|
+
const result = JSON.parse(text);
|
3825
|
+
if (result === null || result === void 0 ? void 0 : result.oidcToken) {
|
3826
|
+
return result.oidcToken;
|
4207
3827
|
}
|
4208
|
-
|
4209
|
-
const
|
4210
|
-
|
4211
|
-
|
4212
|
-
|
4213
|
-
else {
|
4214
|
-
let errorMessage = `${credentialName$1}: Authentication Failed. oidcToken field not detected in the response.`;
|
4215
|
-
if (response.status !== 200) {
|
4216
|
-
errorMessage += `Response = ${JSON.stringify(result)}`;
|
4217
|
-
}
|
4218
|
-
logger$2.error(errorMessage);
|
4219
|
-
throw new AuthenticationError(response.status, errorMessage);
|
3828
|
+
else {
|
3829
|
+
const errorMessage = `${credentialName$1}: Authentication Failed. oidcToken field not detected in the response.`;
|
3830
|
+
let errorDescription = ``;
|
3831
|
+
if (response.status !== 200) {
|
3832
|
+
errorDescription = `Complete response - ${JSON.stringify(result)}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`;
|
4220
3833
|
}
|
4221
|
-
|
4222
|
-
|
4223
|
-
|
4224
|
-
|
4225
|
-
|
3834
|
+
logger$2.error(errorMessage);
|
3835
|
+
logger$2.error(errorDescription);
|
3836
|
+
throw new AuthenticationError(response.status, {
|
3837
|
+
error: errorMessage,
|
3838
|
+
error_description: errorDescription,
|
3839
|
+
});
|
4226
3840
|
}
|
4227
3841
|
}
|
3842
|
+
catch (e) {
|
3843
|
+
const errorDetails = `${credentialName$1}: Authentication Failed. oidcToken field not detected in the response.`;
|
3844
|
+
logger$2.error(`Response from service = ${text} and error message = ${e.message}`);
|
3845
|
+
logger$2.error(errorDetails);
|
3846
|
+
throw new AuthenticationError(response.status, {
|
3847
|
+
error: errorDetails,
|
3848
|
+
error_description: `Response = ${text}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`,
|
3849
|
+
});
|
3850
|
+
}
|
4228
3851
|
}
|
4229
3852
|
|
4230
3853
|
// Copyright (c) Microsoft Corporation.
|
@@ -4294,11 +3917,17 @@ class OnBehalfOfCredential {
|
|
4294
3917
|
const { certificatePath, sendCertificateChain } = options;
|
4295
3918
|
const { getAssertion } = options;
|
4296
3919
|
const { tenantId, clientId, userAssertionToken, additionallyAllowedTenants: additionallyAllowedTenantIds, } = options;
|
4297
|
-
if (!tenantId
|
4298
|
-
|
4299
|
-
|
4300
|
-
|
4301
|
-
throw new
|
3920
|
+
if (!tenantId) {
|
3921
|
+
throw new CredentialUnavailableError(`${credentialName}: tenantId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
|
3922
|
+
}
|
3923
|
+
if (!clientId) {
|
3924
|
+
throw new CredentialUnavailableError(`${credentialName}: clientId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
|
3925
|
+
}
|
3926
|
+
if (!clientSecret && !certificatePath && !getAssertion) {
|
3927
|
+
throw new CredentialUnavailableError(`${credentialName}: You must provide one of clientSecret, certificatePath, or a getAssertion callback but none were provided. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
|
3928
|
+
}
|
3929
|
+
if (!userAssertionToken) {
|
3930
|
+
throw new CredentialUnavailableError(`${credentialName}: userAssertionToken is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
|
4302
3931
|
}
|
4303
3932
|
this.certificatePath = certificatePath;
|
4304
3933
|
this.clientSecret = clientSecret;
|
@@ -4467,7 +4096,7 @@ exports.WorkloadIdentityCredential = WorkloadIdentityCredential;
|
|
4467
4096
|
exports.deserializeAuthenticationRecord = deserializeAuthenticationRecord;
|
4468
4097
|
exports.getBearerTokenProvider = getBearerTokenProvider;
|
4469
4098
|
exports.getDefaultAzureCredential = getDefaultAzureCredential;
|
4470
|
-
exports.logger = logger$
|
4099
|
+
exports.logger = logger$l;
|
4471
4100
|
exports.serializeAuthenticationRecord = serializeAuthenticationRecord;
|
4472
4101
|
exports.useIdentityPlugin = useIdentityPlugin;
|
4473
4102
|
//# sourceMappingURL=index.js.map
|