@azure/identity 4.4.0 → 4.4.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.
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var logger$r = require('@azure/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');
@@ -12,8 +12,6 @@ var fs = require('fs');
12
12
  var os = require('os');
13
13
  var path = require('path');
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');
@@ -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.4.0`;
47
+ const SDK_VERSION = `4.4.1`;
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$q = logger$r.createClientLogger("identity");
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$q) {
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$q) {
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
  }
@@ -497,8 +495,6 @@ const DefaultScopeSuffix = "/.default";
497
495
  const imdsHost = "http://169.254.169.254";
498
496
  const imdsEndpointPath = "/metadata/identity/oauth2/token";
499
497
  const imdsApiVersion = "2018-02-01";
500
- const azureArcAPIVersion = "2019-11-01";
501
- const azureFabricVersion = "2019-07-01-preview";
502
498
 
503
499
  // Copyright (c) Microsoft Corporation.
504
500
  // Licensed under the MIT license.
@@ -590,14 +586,19 @@ class IdentityClient extends coreClient.ServiceClient {
590
586
  } }, options), { userAgentOptions: {
591
587
  userAgentPrefix,
592
588
  }, baseUri }));
589
+ this.allowInsecureConnection = false;
593
590
  this.authorityHost = baseUri;
594
591
  this.abortControllers = new Map();
595
592
  this.allowLoggingAccountIdentifiers = (_b = options === null || options === void 0 ? void 0 : options.loggingOptions) === null || _b === void 0 ? void 0 : _b.allowLoggingAccountIdentifiers;
596
593
  // used for WorkloadIdentity
597
594
  this.tokenCredentialOptions = Object.assign({}, options);
595
+ // used for ManagedIdentity
596
+ if (options === null || options === void 0 ? void 0 : options.allowInsecureConnection) {
597
+ this.allowInsecureConnection = options.allowInsecureConnection;
598
+ }
598
599
  }
599
600
  async sendTokenRequest(request) {
600
- logger$q.info(`IdentityClient: sending token request to [${request.url}]`);
601
+ logger$l.info(`IdentityClient: sending token request to [${request.url}]`);
601
602
  const response = await this.sendRequest(request);
602
603
  if (response.bodyAsText && (response.status === 200 || response.status === 201)) {
603
604
  const parsedBody = JSON.parse(response.bodyAsText);
@@ -612,12 +613,12 @@ class IdentityClient extends coreClient.ServiceClient {
612
613
  },
613
614
  refreshToken: parsedBody.refresh_token,
614
615
  };
615
- logger$q.info(`IdentityClient: [${request.url}] token acquired, expires on ${token.accessToken.expiresOnTimestamp}`);
616
+ logger$l.info(`IdentityClient: [${request.url}] token acquired, expires on ${token.accessToken.expiresOnTimestamp}`);
616
617
  return token;
617
618
  }
618
619
  else {
619
620
  const error = new AuthenticationError(response.status, response.bodyAsText);
620
- logger$q.warning(`IdentityClient: authentication error. HTTP status: ${response.status}, ${error.errorResponse.errorDescription}`);
621
+ logger$l.warning(`IdentityClient: authentication error. HTTP status: ${response.status}, ${error.errorResponse.errorDescription}`);
621
622
  throw error;
622
623
  }
623
624
  }
@@ -625,7 +626,7 @@ class IdentityClient extends coreClient.ServiceClient {
625
626
  if (refreshToken === undefined) {
626
627
  return null;
627
628
  }
628
- logger$q.info(`IdentityClient: refreshing access token with client ID: ${clientId}, scopes: ${scopes} started`);
629
+ logger$l.info(`IdentityClient: refreshing access token with client ID: ${clientId}, scopes: ${scopes} started`);
629
630
  const refreshParams = {
630
631
  grant_type: "refresh_token",
631
632
  client_id: clientId,
@@ -651,7 +652,7 @@ class IdentityClient extends coreClient.ServiceClient {
651
652
  tracingOptions: updatedOptions.tracingOptions,
652
653
  });
653
654
  const response = await this.sendTokenRequest(request);
654
- logger$q.info(`IdentityClient: refreshed token for client ID: ${clientId}`);
655
+ logger$l.info(`IdentityClient: refreshed token for client ID: ${clientId}`);
655
656
  return response;
656
657
  }
657
658
  catch (err) {
@@ -660,11 +661,11 @@ class IdentityClient extends coreClient.ServiceClient {
660
661
  // It's likely that the refresh token has expired, so
661
662
  // return null so that the credential implementation will
662
663
  // initiate the authentication flow again.
663
- logger$q.info(`IdentityClient: interaction required for client ID: ${clientId}`);
664
+ logger$l.info(`IdentityClient: interaction required for client ID: ${clientId}`);
664
665
  return null;
665
666
  }
666
667
  else {
667
- logger$q.warning(`IdentityClient: failed refreshing token for client ID: ${clientId}: ${err}`);
668
+ logger$l.warning(`IdentityClient: failed refreshing token for client ID: ${clientId}: ${err}`);
668
669
  throw err;
669
670
  }
670
671
  }
@@ -712,6 +713,7 @@ class IdentityClient extends coreClient.ServiceClient {
712
713
  url,
713
714
  method: "GET",
714
715
  body: options === null || options === void 0 ? void 0 : options.body,
716
+ allowInsecureConnection: this.allowInsecureConnection,
715
717
  headers: coreRestPipeline.createHttpHeaders(options === null || options === void 0 ? void 0 : options.headers),
716
718
  abortSignal: this.generateAbortSignal(noCorrelationId),
717
719
  });
@@ -729,6 +731,7 @@ class IdentityClient extends coreClient.ServiceClient {
729
731
  method: "POST",
730
732
  body: options === null || options === void 0 ? void 0 : options.body,
731
733
  headers: coreRestPipeline.createHttpHeaders(options === null || options === void 0 ? void 0 : options.headers),
734
+ allowInsecureConnection: this.allowInsecureConnection,
732
735
  // MSAL doesn't send the correlation ID on the get requests.
733
736
  abortSignal: this.generateAbortSignal(this.getCorrelationId(options)),
734
737
  });
@@ -773,10 +776,10 @@ class IdentityClient extends coreClient.ServiceClient {
773
776
  }
774
777
  const base64Metadata = accessToken.split(".")[1];
775
778
  const { appid, upn, tid, oid } = JSON.parse(Buffer.from(base64Metadata, "base64").toString("utf8"));
776
- logger$q.info(`[Authenticated account] Client ID: ${appid}. Tenant ID: ${tid}. User Principal Name: ${upn || unavailableUpn}. Object ID (user): ${oid}`);
779
+ logger$l.info(`[Authenticated account] Client ID: ${appid}. Tenant ID: ${tid}. User Principal Name: ${upn || unavailableUpn}. Object ID (user): ${oid}`);
777
780
  }
778
781
  catch (e) {
779
- logger$q.warning("allowLoggingAccountIdentifiers was set, but we couldn't log the account information. Error:", e.message);
782
+ logger$l.warning("allowLoggingAccountIdentifiers was set, but we couldn't log the account information. Error:", e.message);
780
783
  }
781
784
  }
782
785
  }
@@ -785,7 +788,7 @@ class IdentityClient extends coreClient.ServiceClient {
785
788
  // Licensed under the MIT license.
786
789
  const CommonTenantId = "common";
787
790
  const AzureAccountClientId = "aebc6443-996d-45c2-90f0-388ff96faa56"; // VSC: 'aebc6443-996d-45c2-90f0-388ff96faa56'
788
- const logger$p = credentialLogger("VisualStudioCodeCredential");
791
+ const logger$k = credentialLogger("VisualStudioCodeCredential");
789
792
  let findCredentials = undefined;
790
793
  const vsCodeCredentialControl = {
791
794
  setVsCodeCredentialFinder(finder) {
@@ -838,7 +841,7 @@ function getPropertyFromVSCode(property) {
838
841
  }
839
842
  }
840
843
  catch (e) {
841
- logger$p.info(`Failed to load the Visual Studio Code configuration file. Error: ${e.message}`);
844
+ logger$k.info(`Failed to load the Visual Studio Code configuration file. Error: ${e.message}`);
842
845
  return;
843
846
  }
844
847
  }
@@ -871,7 +874,7 @@ class VisualStudioCodeCredential {
871
874
  const authorityHost = mapVSCodeAuthorityHosts[this.cloudName];
872
875
  this.identityClient = new IdentityClient(Object.assign({ authorityHost }, options));
873
876
  if (options && options.tenantId) {
874
- checkTenantId(logger$p, options.tenantId);
877
+ checkTenantId(logger$k, options.tenantId);
875
878
  this.tenantId = options.tenantId;
876
879
  }
877
880
  else {
@@ -911,7 +914,7 @@ class VisualStudioCodeCredential {
911
914
  async getToken(scopes, options) {
912
915
  var _a, _b;
913
916
  await this.prepareOnce();
914
- const tenantId = processMultiTenantRequest(this.tenantId, options, this.additionallyAllowedTenantIds, logger$p) || this.tenantId;
917
+ const tenantId = processMultiTenantRequest(this.tenantId, options, this.additionallyAllowedTenantIds, logger$k) || this.tenantId;
915
918
  if (findCredentials === undefined) {
916
919
  throw new CredentialUnavailableError([
917
920
  "No implementation of `VisualStudioCodeCredential` is available.",
@@ -925,7 +928,7 @@ class VisualStudioCodeCredential {
925
928
  // Check to make sure the scope we get back is a valid scope
926
929
  if (!scopeString.match(/^[0-9a-zA-Z-.:/]+$/)) {
927
930
  const error = new Error("Invalid scope was specified by the user or calling client");
928
- logger$p.getToken.info(formatError(scopes, error));
931
+ logger$k.getToken.info(formatError(scopes, error));
929
932
  throw error;
930
933
  }
931
934
  if (scopeString.indexOf("offline_access") < 0) {
@@ -945,18 +948,18 @@ class VisualStudioCodeCredential {
945
948
  if (refreshToken) {
946
949
  const tokenResponse = await this.identityClient.refreshAccessToken(tenantId, AzureAccountClientId, scopeString, refreshToken, undefined);
947
950
  if (tokenResponse) {
948
- logger$p.getToken.info(formatSuccess(scopes));
951
+ logger$k.getToken.info(formatSuccess(scopes));
949
952
  return tokenResponse.accessToken;
950
953
  }
951
954
  else {
952
955
  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$p.getToken.info(formatError(scopes, error));
956
+ logger$k.getToken.info(formatError(scopes, error));
954
957
  throw error;
955
958
  }
956
959
  }
957
960
  else {
958
961
  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$p.getToken.info(formatError(scopes, error));
962
+ logger$k.getToken.info(formatError(scopes, error));
960
963
  throw error;
961
964
  }
962
965
  }
@@ -1005,438 +1008,6 @@ function useIdentityPlugin(plugin) {
1005
1008
  plugin(pluginContext);
1006
1009
  }
1007
1010
 
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
1011
  // Copyright (c) Microsoft Corporation.
1441
1012
  // Licensed under the MIT license.
1442
1013
  /**
@@ -1776,6 +1347,41 @@ const imdsMsi = {
1776
1347
  },
1777
1348
  };
1778
1349
 
1350
+ // Copyright (c) Microsoft Corporation.
1351
+ // Licensed under the MIT license.
1352
+ // Matches the default retry configuration in expontentialRetryStrategy.ts
1353
+ const DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 64;
1354
+ /**
1355
+ * An additional policy that retries on 404 errors. The default retry policy does not retry on
1356
+ * 404s, but the IMDS endpoint can return 404s when the token is not yet available. This policy
1357
+ * will retry on 404s with an exponential backoff.
1358
+ *
1359
+ * @param msiRetryConfig - The retry configuration for the MSI credential.
1360
+ * @returns - The policy that will retry on 404s.
1361
+ */
1362
+ function imdsRetryPolicy(msiRetryConfig) {
1363
+ return coreRestPipeline.retryPolicy([
1364
+ {
1365
+ name: "imdsRetryPolicy",
1366
+ retry: ({ retryCount, response }) => {
1367
+ if ((response === null || response === void 0 ? void 0 : response.status) !== 404) {
1368
+ return { skipStrategy: true };
1369
+ }
1370
+ // Exponentially increase the delay each time
1371
+ const exponentialDelay = msiRetryConfig.startDelayInMs * Math.pow(2, retryCount);
1372
+ // Don't let the delay exceed the maximum
1373
+ const clampedExponentialDelay = Math.min(DEFAULT_CLIENT_MAX_RETRY_INTERVAL, exponentialDelay);
1374
+ // Allow the final value to have some "jitter" (within 50% of the delay size) so
1375
+ // that retries across multiple clients don't occur simultaneously.
1376
+ const retryAfterInMs = clampedExponentialDelay / 2 + coreUtil.getRandomIntegerInclusive(0, clampedExponentialDelay / 2);
1377
+ return { retryAfterInMs };
1378
+ },
1379
+ },
1380
+ ], {
1381
+ maxRetries: msiRetryConfig.maxRetries,
1382
+ });
1383
+ }
1384
+
1779
1385
  // Copyright (c) Microsoft Corporation.
1780
1386
  // Licensed under the MIT license.
1781
1387
  /**
@@ -1956,7 +1562,7 @@ function generateMsalConfiguration(clientId, tenantId, msalClientOptions = {}) {
1956
1562
  networkClient: httpClient,
1957
1563
  loggerOptions: {
1958
1564
  loggerCallback: defaultLoggerCallback((_c = msalClientOptions.logger) !== null && _c !== void 0 ? _c : msalLogger),
1959
- logLevel: getMSALLogLevel(logger$r.getLogLevel()),
1565
+ logLevel: getMSALLogLevel(logger$m.getLogLevel()),
1960
1566
  piiLoggingEnabled: (_d = msalClientOptions.loggingOptions) === null || _d === void 0 ? void 0 : _d.enableUnsafeSupportLogging,
1961
1567
  },
1962
1568
  },
@@ -2509,132 +2115,76 @@ const logger$f = credentialLogger(msiName);
2509
2115
  /**
2510
2116
  * Defines how to determine whether the token exchange MSI is available, and also how to retrieve a token from the token exchange MSI.
2511
2117
  */
2512
- function tokenExchangeMsi() {
2513
- return {
2514
- name: "tokenExchangeMsi",
2515
- async isAvailable({ clientId }) {
2516
- const env = process.env;
2517
- const result = Boolean((clientId || env.AZURE_CLIENT_ID) &&
2518
- env.AZURE_TENANT_ID &&
2519
- process.env.AZURE_FEDERATED_TOKEN_FILE);
2520
- if (!result) {
2521
- 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`);
2522
- }
2523
- return result;
2524
- },
2525
- async getToken(configuration, getTokenOptions = {}) {
2526
- const { scopes, clientId } = configuration;
2527
- const identityClientTokenCredentialOptions = {};
2528
- 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 }));
2529
- const token = await workloadIdentityCredential.getToken(scopes, getTokenOptions);
2530
- return token;
2531
- },
2532
- };
2533
- }
2118
+ const tokenExchangeMsi = {
2119
+ name: "tokenExchangeMsi",
2120
+ async isAvailable({ clientId }) {
2121
+ const env = process.env;
2122
+ const result = Boolean((clientId || env.AZURE_CLIENT_ID) &&
2123
+ env.AZURE_TENANT_ID &&
2124
+ process.env.AZURE_FEDERATED_TOKEN_FILE);
2125
+ if (!result) {
2126
+ 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`);
2127
+ }
2128
+ return result;
2129
+ },
2130
+ async getToken(configuration, getTokenOptions = {}) {
2131
+ const { scopes, clientId } = configuration;
2132
+ const identityClientTokenCredentialOptions = {};
2133
+ 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 }));
2134
+ return workloadIdentityCredential.getToken(scopes, getTokenOptions);
2135
+ },
2136
+ };
2534
2137
 
2535
2138
  // Copyright (c) Microsoft Corporation.
2536
2139
  // Licensed under the MIT license.
2537
- const logger$e = credentialLogger("ManagedIdentityCredential");
2538
- class LegacyMsiProvider {
2539
- constructor(clientIdOrOptions, options) {
2140
+ const logger$e = credentialLogger("ManagedIdentityCredential(MSAL)");
2141
+ class MsalMsiProvider {
2142
+ constructor(clientIdOrOptions, options = {}) {
2540
2143
  var _a, _b;
2541
- this.isEndpointUnavailable = null;
2542
- this.isAppTokenProviderInitialized = false;
2543
2144
  this.msiRetryConfig = {
2544
2145
  maxRetries: 5,
2545
2146
  startDelayInMs: 800,
2546
2147
  intervalIncrement: 2,
2547
2148
  };
2548
- let _options;
2149
+ let _options = {};
2549
2150
  if (typeof clientIdOrOptions === "string") {
2550
2151
  this.clientId = clientIdOrOptions;
2551
2152
  _options = options;
2552
2153
  }
2553
2154
  else {
2554
2155
  this.clientId = clientIdOrOptions === null || clientIdOrOptions === void 0 ? void 0 : clientIdOrOptions.clientId;
2555
- _options = clientIdOrOptions;
2156
+ _options = clientIdOrOptions !== null && clientIdOrOptions !== void 0 ? clientIdOrOptions : {};
2556
2157
  }
2557
2158
  this.resourceId = _options === null || _options === void 0 ? void 0 : _options.resourceId;
2558
2159
  // For JavaScript users.
2559
2160
  if (this.clientId && this.resourceId) {
2560
2161
  throw new Error(`ManagedIdentityCredential - Client Id and Resource Id can't be provided at the same time.`);
2561
2162
  }
2163
+ // ManagedIdentity uses http for local requests
2164
+ _options.allowInsecureConnection = true;
2562
2165
  if (((_a = _options === null || _options === void 0 ? void 0 : _options.retryOptions) === null || _a === void 0 ? void 0 : _a.maxRetries) !== undefined) {
2563
2166
  this.msiRetryConfig.maxRetries = _options.retryOptions.maxRetries;
2564
2167
  }
2565
- this.identityClient = new IdentityClient(_options);
2566
- this.isAvailableIdentityClient = new IdentityClient(Object.assign(Object.assign({}, _options), { retryOptions: {
2567
- maxRetries: 0,
2568
- } }));
2569
- /** authority host validation and metadata discovery to be skipped in managed identity
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: [],
2168
+ this.identityClient = new IdentityClient(Object.assign(Object.assign({}, _options), { additionalPolicies: [{ policy: imdsRetryPolicy(this.msiRetryConfig), position: "perCall" }] }));
2169
+ this.managedIdentityApp = new msalCommon.ManagedIdentityApplication({
2170
+ managedIdentityIdParams: {
2171
+ userAssignedClientId: this.clientId,
2172
+ userAssignedResourceId: this.resourceId,
2580
2173
  },
2581
2174
  system: {
2175
+ // todo: proxyUrl?
2176
+ disableInternalRetries: true,
2177
+ networkClient: this.identityClient,
2582
2178
  loggerOptions: {
2583
- logLevel: getMSALLogLevel(logger$r.getLogLevel()),
2179
+ logLevel: getMSALLogLevel(logger$m.getLogLevel()),
2180
+ piiLoggingEnabled: (_b = options.loggingOptions) === null || _b === void 0 ? void 0 : _b.enableUnsafeSupportLogging,
2181
+ loggerCallback: defaultLoggerCallback(logger$e),
2584
2182
  },
2585
2183
  },
2586
2184
  });
2587
- }
2588
- async cachedAvailableMSI(scopes, getTokenOptions) {
2589
- if (this.cachedMSI) {
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
- }
2185
+ this.isAvailableIdentityClient = new IdentityClient(Object.assign(Object.assign({}, _options), { retryOptions: {
2186
+ maxRetries: 0,
2187
+ } }));
2638
2188
  }
2639
2189
  /**
2640
2190
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
@@ -2645,133 +2195,92 @@ class LegacyMsiProvider {
2645
2195
  * @param options - The options used to configure any requests this
2646
2196
  * TokenCredential implementation might make.
2647
2197
  */
2648
- async getToken(scopes, options) {
2649
- let result = null;
2650
- const { span, updatedOptions } = tracingClient.startSpan(`ManagedIdentityCredential.getToken`, options);
2651
- try {
2652
- // isEndpointAvailable can be true, false, or null,
2653
- // If it's null, it means we don't yet know whether
2654
- // the endpoint is available and need to check for it.
2655
- if (this.isEndpointUnavailable !== true) {
2656
- const availableMSI = await this.cachedAvailableMSI(scopes, updatedOptions);
2657
- if (availableMSI.name === "tokenExchangeMsi") {
2658
- result = await this.authenticateManagedIdentity(scopes, updatedOptions);
2659
- }
2660
- else {
2661
- const appTokenParameters = {
2662
- correlationId: this.identityClient.getCorrelationId(),
2663
- tenantId: (options === null || options === void 0 ? void 0 : options.tenantId) || "managed_identity",
2664
- scopes: Array.isArray(scopes) ? scopes : [scopes],
2665
- claims: options === null || options === void 0 ? void 0 : options.claims,
2666
- };
2667
- // Added a check to see if SetAppTokenProvider was already defined.
2668
- this.initializeSetAppTokenProvider();
2669
- const authenticationResult = await this.confidentialApp.acquireTokenByClientCredential(Object.assign({}, appTokenParameters));
2670
- result = this.handleResult(scopes, authenticationResult || undefined);
2198
+ async getToken(scopes, options = {}) {
2199
+ logger$e.getToken.info("Using the MSAL provider for Managed Identity.");
2200
+ const resource = mapScopesToResource(scopes);
2201
+ if (!resource) {
2202
+ throw new CredentialUnavailableError(`ManagedIdentityCredential: Multiple scopes are not supported. Scopes: ${JSON.stringify(scopes)}`);
2203
+ }
2204
+ return tracingClient.withSpan("ManagedIdentityCredential.getToken", options, async () => {
2205
+ try {
2206
+ const isTokenExchangeMsi = await tokenExchangeMsi.isAvailable({
2207
+ scopes,
2208
+ clientId: this.clientId,
2209
+ getTokenOptions: options,
2210
+ identityClient: this.identityClient,
2211
+ resourceId: this.resourceId,
2212
+ });
2213
+ // Most scenarios are handled by MSAL except for two:
2214
+ // AKS pod identity - MSAL does not implement the token exchange flow.
2215
+ // IMDS Endpoint probing - MSAL does not do any probing before trying to get a token.
2216
+ // As a DefaultAzureCredential optimization we probe the IMDS endpoint with a short timeout and no retries before actually trying to get a token
2217
+ // We will continue to implement these features in the Identity library.
2218
+ const identitySource = this.managedIdentityApp.getManagedIdentitySource();
2219
+ 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.
2220
+ if (isTokenExchangeMsi) {
2221
+ // In the AKS scenario we will use the existing tokenExchangeMsi indefinitely.
2222
+ logger$e.getToken.info("Using the token exchange managed identity.");
2223
+ const result = await tokenExchangeMsi.getToken({
2224
+ scopes,
2225
+ clientId: this.clientId,
2226
+ identityClient: this.identityClient,
2227
+ retryConfig: this.msiRetryConfig,
2228
+ resourceId: this.resourceId,
2229
+ });
2230
+ if (result === null) {
2231
+ throw new CredentialUnavailableError("The managed identity endpoint was reached, yet no tokens were received.");
2232
+ }
2233
+ return result;
2671
2234
  }
2672
- if (result === null) {
2673
- // If authenticateManagedIdentity returns null,
2674
- // it means no MSI endpoints are available.
2675
- // If so, we avoid trying to reach to them in future requests.
2676
- this.isEndpointUnavailable = true;
2677
- // It also means that the endpoint answered with either 200 or 201 (see the sendTokenRequest method),
2678
- // yet we had no access token. For this reason, we'll throw once with a specific message:
2679
- const error = new CredentialUnavailableError("The managed identity endpoint was reached, yet no tokens were received.");
2680
- logger$e.getToken.info(formatError(scopes, error));
2681
- throw error;
2235
+ else if (isImdsMsi) {
2236
+ // In the IMDS scenario we will probe the IMDS endpoint to ensure it's available before trying to get a token.
2237
+ // 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.
2238
+ logger$e.getToken.info("Using the IMDS endpoint to probe for availability.");
2239
+ const isAvailable = await imdsMsi.isAvailable({
2240
+ scopes,
2241
+ clientId: this.clientId,
2242
+ getTokenOptions: options,
2243
+ identityClient: this.isAvailableIdentityClient,
2244
+ resourceId: this.resourceId,
2245
+ });
2246
+ if (!isAvailable) {
2247
+ throw new CredentialUnavailableError(`ManagedIdentityCredential: The managed identity endpoint is not available.`);
2248
+ }
2682
2249
  }
2683
- // Since `authenticateManagedIdentity` didn't throw, and the result was not null,
2684
- // We will assume that this endpoint is reachable from this point forward,
2685
- // and avoid pinging again to it.
2686
- this.isEndpointUnavailable = false;
2687
- }
2688
- else {
2689
- // We've previously determined that the endpoint was unavailable,
2690
- // either because it was unreachable or permanently unable to authenticate.
2691
- const error = new CredentialUnavailableError("The managed identity endpoint is not currently available");
2692
- logger$e.getToken.info(formatError(scopes, error));
2693
- throw error;
2694
- }
2695
- logger$e.getToken.info(formatSuccess(scopes));
2696
- return result;
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}`);
2250
+ // If we got this far, it means:
2251
+ // - This is not a tokenExchangeMsi,
2252
+ // - We already probed for IMDS endpoint availability and failed-fast if it's unreachable.
2253
+ // We can proceed normally by calling MSAL for a token.
2254
+ logger$e.getToken.info("Calling into MSAL for managed identity token.");
2255
+ const token = await this.managedIdentityApp.acquireToken({
2256
+ resource,
2257
+ });
2258
+ this.ensureValidMsalToken(scopes, token, options);
2259
+ logger$e.getToken.info(formatSuccess(scopes));
2260
+ return {
2261
+ expiresOnTimestamp: token.expiresOn.getTime(),
2262
+ token: token.accessToken,
2263
+ };
2731
2264
  }
2732
- // 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"
2733
- // rather than just timing out, as expected.
2734
- if (err.statusCode === 403 || err.code === 403) {
2735
- if (err.message.includes("unreachable")) {
2736
- const error = new CredentialUnavailableError(`ManagedIdentityCredential: Unavailable. Network unreachable. Message: ${err.message}`);
2737
- logger$e.getToken.info(formatError(scopes, error));
2738
- throw error;
2265
+ catch (err) {
2266
+ logger$e.getToken.error(formatError(scopes, err));
2267
+ // AuthenticationRequiredError described as Error to enforce authentication after trying to retrieve a token silently.
2268
+ // TODO: why would this _ever_ happen considering we're not trying the silent request in this flow?
2269
+ if (err.name === "AuthenticationRequiredError") {
2270
+ throw err;
2271
+ }
2272
+ if (isNetworkError(err)) {
2273
+ throw new CredentialUnavailableError(`ManagedIdentityCredential: Network unreachable. Message: ${err.message}`);
2739
2274
  }
2740
- }
2741
- // If the error has no status code, we can assume there was no available identity.
2742
- // This will throw silently during any ChainedTokenCredential.
2743
- if (err.statusCode === undefined) {
2744
2275
  throw new CredentialUnavailableError(`ManagedIdentityCredential: Authentication failed. Message ${err.message}`);
2745
2276
  }
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
- };
2277
+ });
2769
2278
  }
2770
2279
  /**
2771
2280
  * Ensures the validity of the MSAL token
2772
2281
  */
2773
2282
  ensureValidMsalToken(scopes, msalToken, getTokenOptions) {
2774
- const error = (message) => {
2283
+ const createError = (message) => {
2775
2284
  logger$e.getToken.info(message);
2776
2285
  return new AuthenticationRequiredError({
2777
2286
  scopes: Array.isArray(scopes) ? scopes : [scopes],
@@ -2780,43 +2289,33 @@ class LegacyMsiProvider {
2780
2289
  });
2781
2290
  };
2782
2291
  if (!msalToken) {
2783
- throw error("No response");
2292
+ throw createError("No response");
2784
2293
  }
2785
2294
  if (!msalToken.expiresOn) {
2786
- throw error(`Response had no "expiresOn" property.`);
2295
+ throw createError(`Response had no "expiresOn" property.`);
2787
2296
  }
2788
2297
  if (!msalToken.accessToken) {
2789
- throw error(`Response had no "accessToken" property.`);
2298
+ throw createError(`Response had no "accessToken" property.`);
2790
2299
  }
2791
2300
  }
2792
- initializeSetAppTokenProvider() {
2793
- if (!this.isAppTokenProviderInitialized) {
2794
- this.confidentialApp.SetAppTokenProvider(async (appTokenProviderParameters) => {
2795
- logger$e.info(`SetAppTokenProvider invoked with parameters- ${JSON.stringify(appTokenProviderParameters)}`);
2796
- const getTokenOptions = Object.assign({}, appTokenProviderParameters);
2797
- logger$e.info(`authenticateManagedIdentity invoked with scopes- ${JSON.stringify(appTokenProviderParameters.scopes)} and getTokenOptions - ${JSON.stringify(getTokenOptions)}`);
2798
- const resultToken = await this.authenticateManagedIdentity(appTokenProviderParameters.scopes, getTokenOptions);
2799
- if (resultToken) {
2800
- logger$e.info(`SetAppTokenProvider will save the token in cache`);
2801
- const expiresInSeconds = (resultToken === null || resultToken === void 0 ? void 0 : resultToken.expiresOnTimestamp)
2802
- ? Math.floor((resultToken.expiresOnTimestamp - Date.now()) / 1000)
2803
- : 0;
2804
- return {
2805
- accessToken: resultToken === null || resultToken === void 0 ? void 0 : resultToken.token,
2806
- expiresInSeconds,
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;
2301
+ }
2302
+ function isNetworkError(err) {
2303
+ // MSAL error
2304
+ if (err.errorCode === "network_error") {
2305
+ return true;
2306
+ }
2307
+ // Probe errors
2308
+ if (err.code === "ENETUNREACH" || err.code === "EHOSTUNREACH") {
2309
+ return true;
2310
+ }
2311
+ // 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"
2312
+ // rather than just timing out, as expected.
2313
+ if (err.statusCode === 403 || err.code === 403) {
2314
+ if (err.message.includes("unreachable")) {
2315
+ return true;
2818
2316
  }
2819
2317
  }
2318
+ return false;
2820
2319
  }
2821
2320
 
2822
2321
  // Copyright (c) Microsoft Corporation.
@@ -2835,7 +2334,11 @@ class ManagedIdentityCredential {
2835
2334
  * @hidden
2836
2335
  */
2837
2336
  constructor(clientIdOrOptions, options) {
2838
- this.implProvider = new LegacyMsiProvider(clientIdOrOptions, options);
2337
+ // https://github.com/Azure/azure-sdk-for-js/issues/30189
2338
+ // If needed, you may release a hotfix to quickly rollback to the legacy implementation by changing the following line to:
2339
+ // this.implProvider = new LegacyMsiProvider(clientIdOrOptions, options);
2340
+ // Once stabilized, you can remove the legacy implementation and inline the msalMsiProvider code here as a drop-in replacement.
2341
+ this.implProvider = new MsalMsiProvider(clientIdOrOptions, options);
2839
2342
  }
2840
2343
  /**
2841
2344
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
@@ -3366,12 +2869,7 @@ class AzurePowerShellCredential {
3366
2869
  ],
3367
2870
  ]);
3368
2871
  const result = results[1];
3369
- try {
3370
- return JSON.parse(result);
3371
- }
3372
- catch (e) {
3373
- throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);
3374
- }
2872
+ return parseJsonToken(result);
3375
2873
  }
3376
2874
  throw new Error(`Unable to execute PowerShell. Ensure that it is installed in your system`);
3377
2875
  }
@@ -3418,6 +2916,38 @@ class AzurePowerShellCredential {
3418
2916
  });
3419
2917
  }
3420
2918
  }
2919
+ /**
2920
+ *
2921
+ * @internal
2922
+ */
2923
+ async function parseJsonToken(result) {
2924
+ const jsonRegex = /{[^{}]*}/g;
2925
+ const matches = result.match(jsonRegex);
2926
+ let resultWithoutToken = result;
2927
+ if (matches) {
2928
+ try {
2929
+ for (const item of matches) {
2930
+ try {
2931
+ const jsonContent = JSON.parse(item);
2932
+ if (jsonContent === null || jsonContent === void 0 ? void 0 : jsonContent.Token) {
2933
+ resultWithoutToken = resultWithoutToken.replace(item, "");
2934
+ if (resultWithoutToken) {
2935
+ logger$b.getToken.warning(resultWithoutToken);
2936
+ }
2937
+ return jsonContent;
2938
+ }
2939
+ }
2940
+ catch (e) {
2941
+ continue;
2942
+ }
2943
+ }
2944
+ }
2945
+ catch (e) {
2946
+ throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);
2947
+ }
2948
+ }
2949
+ throw new Error(`No access token found in the output. Received output: ${result}`);
2950
+ }
3421
2951
 
3422
2952
  // Copyright (c) Microsoft Corporation.
3423
2953
  // Licensed under the MIT license.
@@ -4200,30 +3730,45 @@ class AzurePipelinesCredential {
4200
3730
  }),
4201
3731
  });
4202
3732
  const response = await this.identityClient.sendRequest(request);
4203
- const text = response.bodyAsText;
4204
- if (!text) {
4205
- logger$2.error(`${credentialName$1}: Authenticated Failed. Received null token from OIDC request. Response status- ${response.status}. Complete response - ${JSON.stringify(response)}`);
4206
- throw new AuthenticationError(response.status, `${credentialName$1}: Authenticated Failed. Received null token from OIDC request. Response status- ${response.status}. Complete response - ${JSON.stringify(response)}`);
3733
+ return handleOidcResponse(response);
3734
+ }
3735
+ }
3736
+ function handleOidcResponse(response) {
3737
+ const text = response.bodyAsText;
3738
+ if (!text) {
3739
+ logger$2.error(`${credentialName$1}: Authentication Failed. Received null token from OIDC request. Response status- ${response.status}. Complete response - ${JSON.stringify(response)}`);
3740
+ throw new AuthenticationError(response.status, {
3741
+ error: `${credentialName$1}: Authentication Failed. Received null token from OIDC request.`,
3742
+ error_description: `${JSON.stringify(response)}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`,
3743
+ });
3744
+ }
3745
+ try {
3746
+ const result = JSON.parse(text);
3747
+ if (result === null || result === void 0 ? void 0 : result.oidcToken) {
3748
+ return result.oidcToken;
4207
3749
  }
4208
- try {
4209
- const result = JSON.parse(text);
4210
- if (result === null || result === void 0 ? void 0 : result.oidcToken) {
4211
- return result.oidcToken;
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);
3750
+ else {
3751
+ const errorMessage = `${credentialName$1}: Authentication Failed. oidcToken field not detected in the response.`;
3752
+ let errorDescription = ``;
3753
+ if (response.status !== 200) {
3754
+ errorDescription = `Complete response - ${JSON.stringify(result)}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`;
4220
3755
  }
3756
+ logger$2.error(errorMessage);
3757
+ logger$2.error(errorDescription);
3758
+ throw new AuthenticationError(response.status, {
3759
+ error: errorMessage,
3760
+ error_description: errorDescription,
3761
+ });
4221
3762
  }
4222
- catch (e) {
4223
- logger$2.error(e.message);
4224
- logger$2.error(`${credentialName$1}: Authentication Failed. oidcToken field not detected in the response. Response = ${text}`);
4225
- throw new AuthenticationError(response.status, `${credentialName$1}: Authentication Failed. oidcToken field not detected in the response. Response = ${text}`);
4226
- }
3763
+ }
3764
+ catch (e) {
3765
+ const errorDetails = `${credentialName$1}: Authentication Failed. oidcToken field not detected in the response.`;
3766
+ logger$2.error(`Response from service = ${text} and error message = ${e.message}`);
3767
+ logger$2.error(errorDetails);
3768
+ throw new AuthenticationError(response.status, {
3769
+ error: errorDetails,
3770
+ error_description: `Response = ${text}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`,
3771
+ });
4227
3772
  }
4228
3773
  }
4229
3774
 
@@ -4467,7 +4012,7 @@ exports.WorkloadIdentityCredential = WorkloadIdentityCredential;
4467
4012
  exports.deserializeAuthenticationRecord = deserializeAuthenticationRecord;
4468
4013
  exports.getBearerTokenProvider = getBearerTokenProvider;
4469
4014
  exports.getDefaultAzureCredential = getDefaultAzureCredential;
4470
- exports.logger = logger$q;
4015
+ exports.logger = logger$l;
4471
4016
  exports.serializeAuthenticationRecord = serializeAuthenticationRecord;
4472
4017
  exports.useIdentityPlugin = useIdentityPlugin;
4473
4018
  //# sourceMappingURL=index.js.map