@azure/identity 4.4.0 → 4.5.0-alpha.20240813.2

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