@azure/identity 4.3.1-alpha.20240702.3 → 4.4.1

Sign up to get free protection for your applications and to get access to all the features.
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.3.1`;
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