@azure/identity 2.0.0-beta.5 → 2.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of @azure/identity might be problematic. Click here for more details.

Files changed (81) hide show
  1. package/CHANGELOG.md +49 -10
  2. package/README.md +26 -21
  3. package/dist/index.js +461 -211
  4. package/dist/index.js.map +1 -1
  5. package/dist-esm/src/client/errors.js +1 -1
  6. package/dist-esm/src/client/errors.js.map +1 -1
  7. package/dist-esm/src/client/identityClient.js +2 -6
  8. package/dist-esm/src/client/identityClient.js.map +1 -1
  9. package/dist-esm/src/credentials/applicationCredential.js +0 -3
  10. package/dist-esm/src/credentials/applicationCredential.js.map +1 -1
  11. package/dist-esm/src/credentials/authorizationCodeCredential.js +12 -76
  12. package/dist-esm/src/credentials/authorizationCodeCredential.js.map +1 -1
  13. package/dist-esm/src/credentials/chainedTokenCredential.js +4 -3
  14. package/dist-esm/src/credentials/chainedTokenCredential.js.map +1 -1
  15. package/dist-esm/src/credentials/clientCertificateCredential.js +3 -0
  16. package/dist-esm/src/credentials/clientCertificateCredential.js.map +1 -1
  17. package/dist-esm/src/credentials/clientSecretCredential.browser.js +1 -4
  18. package/dist-esm/src/credentials/clientSecretCredential.browser.js.map +1 -1
  19. package/dist-esm/src/credentials/clientSecretCredential.js +3 -0
  20. package/dist-esm/src/credentials/clientSecretCredential.js.map +1 -1
  21. package/dist-esm/src/credentials/credentialPersistenceOptions.js.map +1 -1
  22. package/dist-esm/src/credentials/defaultAzureCredential.js +5 -8
  23. package/dist-esm/src/credentials/defaultAzureCredential.js.map +1 -1
  24. package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js +21 -10
  25. package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js.map +1 -1
  26. package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js +23 -12
  27. package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js.map +1 -1
  28. package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js +22 -11
  29. package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js.map +1 -1
  30. package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js +19 -7
  31. package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js.map +1 -1
  32. package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js +29 -20
  33. package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js.map +1 -1
  34. package/dist-esm/src/credentials/managedIdentityCredential/index.js +13 -10
  35. package/dist-esm/src/credentials/managedIdentityCredential/index.js.map +1 -1
  36. package/dist-esm/src/credentials/managedIdentityCredential/models.js.map +1 -1
  37. package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js +82 -0
  38. package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js.map +1 -0
  39. package/dist-esm/src/credentials/managedIdentityCredential/utils.js +10 -5
  40. package/dist-esm/src/credentials/managedIdentityCredential/utils.js.map +1 -1
  41. package/dist-esm/src/credentials/onBehalfOfCredential.browser.js +17 -0
  42. package/dist-esm/src/credentials/onBehalfOfCredential.browser.js.map +1 -0
  43. package/dist-esm/src/credentials/onBehalfOfCredential.js +62 -0
  44. package/dist-esm/src/credentials/onBehalfOfCredential.js.map +1 -0
  45. package/dist-esm/src/credentials/{visualStudioCodeCredentialExtension.js → onBehalfOfCredentialOptions.js} +1 -1
  46. package/dist-esm/src/credentials/onBehalfOfCredentialOptions.js.map +1 -0
  47. package/dist-esm/src/credentials/usernamePasswordCredential.browser.js +10 -13
  48. package/dist-esm/src/credentials/usernamePasswordCredential.browser.js.map +1 -1
  49. package/dist-esm/src/credentials/usernamePasswordCredential.js +3 -0
  50. package/dist-esm/src/credentials/usernamePasswordCredential.js.map +1 -1
  51. package/dist-esm/src/credentials/visualStudioCodeCredential.browser.js +1 -1
  52. package/dist-esm/src/credentials/visualStudioCodeCredential.browser.js.map +1 -1
  53. package/dist-esm/src/credentials/visualStudioCodeCredential.js +11 -1
  54. package/dist-esm/src/credentials/visualStudioCodeCredential.js.map +1 -1
  55. package/dist-esm/src/credentials/visualStudioCodeCredentialPlugin.js +4 -0
  56. package/dist-esm/src/credentials/visualStudioCodeCredentialPlugin.js.map +1 -0
  57. package/dist-esm/src/index.js +2 -1
  58. package/dist-esm/src/index.js.map +1 -1
  59. package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js +41 -0
  60. package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js.map +1 -0
  61. package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js +48 -29
  62. package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js.map +1 -1
  63. package/dist-esm/src/msal/nodeFlows/msalClientSecret.js.map +1 -1
  64. package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js +56 -0
  65. package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js.map +1 -0
  66. package/dist-esm/src/msal/nodeFlows/nodeCommon.js +6 -1
  67. package/dist-esm/src/msal/nodeFlows/nodeCommon.js.map +1 -1
  68. package/dist-esm/src/msal/nodeFlows/tokenCachePersistenceOptions.js.map +1 -1
  69. package/dist-esm/src/plugins/consumer.browser.js +7 -0
  70. package/dist-esm/src/plugins/consumer.browser.js.map +1 -0
  71. package/dist-esm/src/{extensions → plugins}/consumer.js +12 -12
  72. package/dist-esm/src/plugins/consumer.js.map +1 -0
  73. package/dist-esm/src/{extensions → plugins}/provider.js +0 -0
  74. package/dist-esm/src/plugins/provider.js.map +1 -0
  75. package/package.json +10 -12
  76. package/types/identity.d.ts +126 -41
  77. package/dist-esm/src/credentials/visualStudioCodeCredentialExtension.js.map +0 -1
  78. package/dist-esm/src/extensions/consumer.browser.js +0 -7
  79. package/dist-esm/src/extensions/consumer.browser.js.map +0 -1
  80. package/dist-esm/src/extensions/consumer.js.map +0 -1
  81. package/dist-esm/src/extensions/provider.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"defaultAzureCredential.js","sourceRoot":"","sources":["../../../src/credentials/defaultAzureCredential.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAMlC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAExE,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AA4B1E;;;;;GAKG;AACH,MAAM,OAAO,gCAAiC,SAAQ,yBAAyB;IAC7E,YAAY,OAAuC;;QACjD,MAAM,uBAAuB,GAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,uBAAuB,mCAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;QAChG,IAAI,uBAAuB,KAAK,SAAS,EAAE;YACzC,KAAK,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;SACzC;aAAM;YACL,KAAK,CAAC,OAAO,CAAC,CAAC;SAChB;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAmC;IAChE,qBAAqB;IACrB,gCAAgC;IAChC,0BAA0B;IAC1B,kBAAkB;IAClB,yBAAyB;CAC1B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,OAAO,sBAAuB,SAAQ,sBAAsB;IAChE;;;;OAIG;IACH,YAAY,OAAuC;QACjD,KAAK,CAAC,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC9D,IAAI,CAAC,kBAAkB;YACrB,oFAAoF,CAAC;IACzF,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { TokenCredential } from \"@azure/core-auth\";\n\nimport { TokenCredentialOptions } from \"../client/identityClient\";\n\nimport { ChainedTokenCredential } from \"./chainedTokenCredential\";\n\nimport { AzureCliCredential } from \"./azureCliCredential\";\nimport { AzurePowerShellCredential } from \"./azurePowerShellCredential\";\nimport { EnvironmentCredential } from \"./environmentCredential\";\nimport { ManagedIdentityCredential } from \"./managedIdentityCredential\";\nimport { CredentialPersistenceOptions } from \"./credentialPersistenceOptions\";\nimport { VisualStudioCodeCredential } from \"./visualStudioCodeCredential\";\n\n/**\n * Provides options to configure the {@link DefaultAzureCredential} class.\n */\nexport interface DefaultAzureCredentialOptions\n extends TokenCredentialOptions,\n CredentialPersistenceOptions {\n /**\n * Optionally pass in a Tenant ID to be used as part of the credential.\n * By default it may use a generic tenant ID depending on the underlying credential.\n */\n tenantId?: string;\n /**\n * Optionally pass in a user assigned client ID to be used by the {@link ManagedIdentityCredential}.\n * This client ID can also be passed through to the {@link ManagedIdentityCredential} through the environment variable: AZURE_CLIENT_ID.\n */\n managedIdentityClientId?: string;\n}\n\n/**\n * The type of a class that implements TokenCredential and accepts\n * `DefaultAzureCredentialOptions`.\n */\ninterface DefaultCredentialConstructor {\n new (options?: DefaultAzureCredentialOptions): TokenCredential;\n}\n\n/**\n * A shim around ManagedIdentityCredential that adapts it to accept\n * `DefaultAzureCredentialOptions`.\n *\n * @internal\n */\nexport class DefaultManagedIdentityCredential extends ManagedIdentityCredential {\n constructor(options?: DefaultAzureCredentialOptions) {\n const managedIdentityClientId = options?.managedIdentityClientId ?? process.env.AZURE_CLIENT_ID;\n if (managedIdentityClientId !== undefined) {\n super(managedIdentityClientId, options);\n } else {\n super(options);\n }\n }\n}\n\nexport const defaultCredentials: DefaultCredentialConstructor[] = [\n EnvironmentCredential,\n DefaultManagedIdentityCredential,\n VisualStudioCodeCredential,\n AzureCliCredential,\n AzurePowerShellCredential\n];\n\n/**\n * Provides a default {@link ChainedTokenCredential} configuration that should\n * work for most applications that use the Azure SDK. The following credential\n * types will be tried, in order:\n *\n * - {@link EnvironmentCredential}\n * - {@link ManagedIdentityCredential}\n * - {@link VisualStudioCodeCredential}\n * - {@link AzureCliCredential}\n * - {@link AzurePowerShellCredential}\n *\n * Consult the documentation of these credential types for more information\n * on how they attempt authentication.\n *\n * **Note**: `VisualStudioCodeCredential` is provided by an extension package:\n * `@azure/identity-vscode`. If this package is not installed and registered\n * using the extension API (`useIdentityExtension`), then authentication using\n * `VisualStudioCodeCredential` will not be available.\n *\n * Azure Identity extensions may add credential types to the default credential\n * stack.\n */\nexport class DefaultAzureCredential extends ChainedTokenCredential {\n /**\n * Creates an instance of the DefaultAzureCredential class.\n *\n * @param options - Optional parameters. See {@link DefaultAzureCredentialOptions}.\n */\n constructor(options?: DefaultAzureCredentialOptions) {\n super(...defaultCredentials.map((ctor) => new ctor(options)));\n this.UnavailableMessage =\n \"DefaultAzureCredential => failed to retrieve a token from the included credentials\";\n }\n}\n"]}
1
+ {"version":3,"file":"defaultAzureCredential.js","sourceRoot":"","sources":["../../../src/credentials/defaultAzureCredential.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAMlC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAExE,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AA4B1E;;;;;GAKG;AACH,MAAM,OAAO,gCAAiC,SAAQ,yBAAyB;IAC7E,YAAY,OAAuC;;QACjD,MAAM,uBAAuB,GAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,uBAAuB,mCAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;QAChG,IAAI,uBAAuB,KAAK,SAAS,EAAE;YACzC,KAAK,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;SACzC;aAAM;YACL,KAAK,CAAC,OAAO,CAAC,CAAC;SAChB;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAmC;IAChE,qBAAqB;IACrB,gCAAgC;IAChC,0BAA0B;IAC1B,kBAAkB;IAClB,yBAAyB;CAC1B,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,sBAAuB,SAAQ,sBAAsB;IAChE;;;;;;;;;OASG;IACH,YAAY,OAAuC;QACjD,KAAK,CAAC,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC9D,IAAI,CAAC,kBAAkB;YACrB,oFAAoF,CAAC;IACzF,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { TokenCredential } from \"@azure/core-auth\";\n\nimport { TokenCredentialOptions } from \"../client/identityClient\";\n\nimport { ChainedTokenCredential } from \"./chainedTokenCredential\";\n\nimport { AzureCliCredential } from \"./azureCliCredential\";\nimport { AzurePowerShellCredential } from \"./azurePowerShellCredential\";\nimport { EnvironmentCredential } from \"./environmentCredential\";\nimport { ManagedIdentityCredential } from \"./managedIdentityCredential\";\nimport { CredentialPersistenceOptions } from \"./credentialPersistenceOptions\";\nimport { VisualStudioCodeCredential } from \"./visualStudioCodeCredential\";\n\n/**\n * Provides options to configure the {@link DefaultAzureCredential} class.\n */\nexport interface DefaultAzureCredentialOptions\n extends TokenCredentialOptions,\n CredentialPersistenceOptions {\n /**\n * Optionally pass in a Tenant ID to be used as part of the credential.\n * By default it may use a generic tenant ID depending on the underlying credential.\n */\n tenantId?: string;\n /**\n * Optionally pass in a user assigned client ID to be used by the {@link ManagedIdentityCredential}.\n * This client ID can also be passed through to the {@link ManagedIdentityCredential} through the environment variable: AZURE_CLIENT_ID.\n */\n managedIdentityClientId?: string;\n}\n\n/**\n * The type of a class that implements TokenCredential and accepts\n * `DefaultAzureCredentialOptions`.\n */\ninterface DefaultCredentialConstructor {\n new (options?: DefaultAzureCredentialOptions): TokenCredential;\n}\n\n/**\n * A shim around ManagedIdentityCredential that adapts it to accept\n * `DefaultAzureCredentialOptions`.\n *\n * @internal\n */\nexport class DefaultManagedIdentityCredential extends ManagedIdentityCredential {\n constructor(options?: DefaultAzureCredentialOptions) {\n const managedIdentityClientId = options?.managedIdentityClientId ?? process.env.AZURE_CLIENT_ID;\n if (managedIdentityClientId !== undefined) {\n super(managedIdentityClientId, options);\n } else {\n super(options);\n }\n }\n}\n\nexport const defaultCredentials: DefaultCredentialConstructor[] = [\n EnvironmentCredential,\n DefaultManagedIdentityCredential,\n VisualStudioCodeCredential,\n AzureCliCredential,\n AzurePowerShellCredential\n];\n\n/**\n * Provides a default {@link ChainedTokenCredential} configuration that should\n * work for most applications that use the Azure SDK. The following credential\n * types will be tried, in order:\n *\n * - {@link EnvironmentCredential}\n * - {@link ManagedIdentityCredential}\n * - {@link VisualStudioCodeCredential}\n * - {@link AzureCliCredential}\n * - {@link AzurePowerShellCredential}\n *\n * Consult the documentation of these credential types for more information\n * on how they attempt authentication.\n */\nexport class DefaultAzureCredential extends ChainedTokenCredential {\n /**\n * Creates an instance of the DefaultAzureCredential class.\n *\n * **Note**: `VisualStudioCodeCredential` is provided by a plugin package:\n * `@azure/identity-vscode`. If this package is not installed and registered\n * using the plugin API (`useIdentityPlugin`), then authentication using\n * `VisualStudioCodeCredential` will not be available.\n *\n * @param options - Optional parameters. See {@link DefaultAzureCredentialOptions}.\n */\n constructor(options?: DefaultAzureCredentialOptions) {\n super(...defaultCredentials.map((ctor) => new ctor(options)));\n this.UnavailableMessage =\n \"DefaultAzureCredential => failed to retrieve a token from the included credentials\";\n }\n}\n"]}
@@ -2,14 +2,19 @@
2
2
  // Licensed under the MIT license.
3
3
  import { createHttpHeaders } from "@azure/core-rest-pipeline";
4
4
  import { credentialLogger } from "../../util/logging";
5
- import { msiGenericGetToken } from "./utils";
6
- const logger = credentialLogger("ManagedIdentityCredential - AppServiceMSI 2017");
5
+ import { mapScopesToResource, msiGenericGetToken } from "./utils";
6
+ const msiName = "ManagedIdentityCredential - AppServiceMSI 2017";
7
+ const logger = credentialLogger(msiName);
7
8
  function expiresInParser(requestBody) {
8
9
  // Parse a date format like "06/20/2019 02:57:58 +00:00" and
9
10
  // convert it into a JavaScript-formatted date
10
11
  return Date.parse(requestBody.expires_on);
11
12
  }
12
- function prepareRequestOptions(resource, clientId) {
13
+ function prepareRequestOptions(scopes, clientId) {
14
+ const resource = mapScopesToResource(scopes);
15
+ if (!resource) {
16
+ throw new Error(`${msiName}: Multiple scopes are not supported.`);
17
+ }
13
18
  const queryParameters = {
14
19
  resource,
15
20
  "api-version": "2017-09-01"
@@ -20,10 +25,10 @@ function prepareRequestOptions(resource, clientId) {
20
25
  const query = new URLSearchParams(queryParameters);
21
26
  // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
22
27
  if (!process.env.MSI_ENDPOINT) {
23
- throw new Error("Missing environment variable: MSI_ENDPOINT");
28
+ throw new Error(`${msiName}: Missing environment variable: MSI_ENDPOINT`);
24
29
  }
25
30
  if (!process.env.MSI_SECRET) {
26
- throw new Error("Missing environment variable: MSI_SECRET");
31
+ throw new Error(`${msiName}: Missing environment variable: MSI_SECRET`);
27
32
  }
28
33
  return {
29
34
  url: `${process.env.MSI_ENDPOINT}?${query.toString()}`,
@@ -35,17 +40,23 @@ function prepareRequestOptions(resource, clientId) {
35
40
  };
36
41
  }
37
42
  export const appServiceMsi2017 = {
38
- async isAvailable() {
43
+ async isAvailable(scopes) {
44
+ const resource = mapScopesToResource(scopes);
45
+ if (!resource) {
46
+ logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
47
+ return false;
48
+ }
39
49
  const env = process.env;
40
50
  const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);
41
51
  if (!result) {
42
- logger.info("The Azure App Service MSI 2017 is unavailable.");
52
+ logger.info(`${msiName}: Unavailable. The environment variables needed are: MSI_ENDPOINT and MSI_SECRET.`);
43
53
  }
44
54
  return result;
45
55
  },
46
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
47
- logger.info(`Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`);
48
- return msiGenericGetToken(identityClient, prepareRequestOptions(resource, clientId), expiresInParser, getTokenOptions);
56
+ async getToken(configuration, getTokenOptions = {}) {
57
+ const { identityClient, scopes, clientId } = configuration;
58
+ logger.info(`${msiName}: Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`);
59
+ return msiGenericGetToken(identityClient, prepareRequestOptions(scopes, clientId), expiresInParser, getTokenOptions);
49
60
  }
50
61
  };
51
62
  //# sourceMappingURL=appServiceMsi2017.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"appServiceMsi2017.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/appServiceMsi2017.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,iBAAiB,EAA0B,MAAM,2BAA2B,CAAC;AAGtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE7C,MAAM,MAAM,GAAG,gBAAgB,CAAC,gDAAgD,CAAC,CAAC;AAElF,SAAS,eAAe,CAAC,WAAgB;IACvC,4DAA4D;IAC5D,8CAA8C;IAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,qBAAqB,CAAC,QAAgB,EAAE,QAAiB;IAChE,MAAM,eAAe,GAAQ;QAC3B,QAAQ;QACR,aAAa,EAAE,YAAY;KAC5B,CAAC;IAEF,IAAI,QAAQ,EAAE;QACZ,eAAe,CAAC,QAAQ,GAAG,QAAQ,CAAC;KACrC;IAED,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,eAAe,CAAC,CAAC;IAEnD,wIAAwI;IACxI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE;QAC7B,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;KAC/D;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE;QAC3B,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;KAC7D;IAED,OAAO;QACL,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAE;QACtD,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,iBAAiB,CAAC;YACzB,MAAM,EAAE,kBAAkB;YAC1B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;SAC/B,CAAC;KACH,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAQ;IACpC,KAAK,CAAC,WAAW;QACf,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;QACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3D,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;SAC/D;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,KAAK,CAAC,QAAQ,CACZ,cAA8B,EAC9B,QAAgB,EAChB,QAAiB,EACjB,kBAAmC,EAAE;QAErC,MAAM,CAAC,IAAI,CACT,yFAAyF,OAAO,CAAC,GAAG,CAAC,YAAY,6BAA6B,CAC/I,CAAC;QAEF,OAAO,kBAAkB,CACvB,cAAc,EACd,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,CAAC,EACzC,eAAe,EACf,eAAe,CAChB,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { createHttpHeaders, PipelineRequestOptions } from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { IdentityClient } from \"../../client/identityClient\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { MSI } from \"./models\";\nimport { msiGenericGetToken } from \"./utils\";\n\nconst logger = credentialLogger(\"ManagedIdentityCredential - AppServiceMSI 2017\");\n\nfunction expiresInParser(requestBody: any): number {\n // Parse a date format like \"06/20/2019 02:57:58 +00:00\" and\n // convert it into a JavaScript-formatted date\n return Date.parse(requestBody.expires_on);\n}\n\nfunction prepareRequestOptions(resource: string, clientId?: string): PipelineRequestOptions {\n const queryParameters: any = {\n resource,\n \"api-version\": \"2017-09-01\"\n };\n\n if (clientId) {\n queryParameters.clientid = clientId;\n }\n\n const query = new URLSearchParams(queryParameters);\n\n // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.\n if (!process.env.MSI_ENDPOINT) {\n throw new Error(\"Missing environment variable: MSI_ENDPOINT\");\n }\n if (!process.env.MSI_SECRET) {\n throw new Error(\"Missing environment variable: MSI_SECRET\");\n }\n\n return {\n url: `${process.env.MSI_ENDPOINT}?${query.toString()}`,\n method: \"GET\",\n headers: createHttpHeaders({\n Accept: \"application/json\",\n secret: process.env.MSI_SECRET\n })\n };\n}\n\nexport const appServiceMsi2017: MSI = {\n async isAvailable(): Promise<boolean> {\n const env = process.env;\n const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);\n if (!result) {\n logger.info(\"The Azure App Service MSI 2017 is unavailable.\");\n }\n return result;\n },\n async getToken(\n identityClient: IdentityClient,\n resource: string,\n clientId?: string,\n getTokenOptions: GetTokenOptions = {}\n ): Promise<AccessToken | null> {\n logger.info(\n `Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`\n );\n\n return msiGenericGetToken(\n identityClient,\n prepareRequestOptions(resource, clientId),\n expiresInParser,\n getTokenOptions\n );\n }\n};\n"]}
1
+ {"version":3,"file":"appServiceMsi2017.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/appServiceMsi2017.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,iBAAiB,EAA0B,MAAM,2BAA2B,CAAC;AAEtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElE,MAAM,OAAO,GAAG,gDAAgD,CAAC;AACjE,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAEzC,SAAS,eAAe,CAAC,WAAgB;IACvC,4DAA4D;IAC5D,8CAA8C;IAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,qBAAqB,CAC5B,MAAyB,EACzB,QAAiB;IAEjB,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,CAAC,QAAQ,EAAE;QACb,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,sCAAsC,CAAC,CAAC;KACnE;IAED,MAAM,eAAe,GAAQ;QAC3B,QAAQ;QACR,aAAa,EAAE,YAAY;KAC5B,CAAC;IAEF,IAAI,QAAQ,EAAE;QACZ,eAAe,CAAC,QAAQ,GAAG,QAAQ,CAAC;KACrC;IAED,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,eAAe,CAAC,CAAC;IAEnD,wIAAwI;IACxI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE;QAC7B,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,8CAA8C,CAAC,CAAC;KAC3E;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE;QAC3B,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,4CAA4C,CAAC,CAAC;KACzE;IAED,OAAO;QACL,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAE;QACtD,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,iBAAiB,CAAC;YACzB,MAAM,EAAE,kBAAkB;YAC1B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;SAC/B,CAAC;KACH,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAQ;IACpC,KAAK,CAAC,WAAW,CAAC,MAAM;QACtB,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,EAAE;YACb,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,mDAAmD,CAAC,CAAC;YAC3E,OAAO,KAAK,CAAC;SACd;QACD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;QACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3D,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,CAAC,IAAI,CACT,GAAG,OAAO,mFAAmF,CAC9F,CAAC;SACH;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,KAAK,CAAC,QAAQ,CACZ,aAA+B,EAC/B,kBAAmC,EAAE;QAErC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC;QAE3D,MAAM,CAAC,IAAI,CACT,GAAG,OAAO,2FAA2F,OAAO,CAAC,GAAG,CAAC,YAAY,6BAA6B,CAC3J,CAAC;QAEF,OAAO,kBAAkB,CACvB,cAAc,EACd,qBAAqB,CAAC,MAAM,EAAE,QAAQ,CAAC,EACvC,eAAe,EACf,eAAe,CAChB,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { createHttpHeaders, PipelineRequestOptions } from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { mapScopesToResource, msiGenericGetToken } from \"./utils\";\n\nconst msiName = \"ManagedIdentityCredential - AppServiceMSI 2017\";\nconst logger = credentialLogger(msiName);\n\nfunction expiresInParser(requestBody: any): number {\n // Parse a date format like \"06/20/2019 02:57:58 +00:00\" and\n // convert it into a JavaScript-formatted date\n return Date.parse(requestBody.expires_on);\n}\n\nfunction prepareRequestOptions(\n scopes: string | string[],\n clientId?: string\n): PipelineRequestOptions {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n throw new Error(`${msiName}: Multiple scopes are not supported.`);\n }\n\n const queryParameters: any = {\n resource,\n \"api-version\": \"2017-09-01\"\n };\n\n if (clientId) {\n queryParameters.clientid = clientId;\n }\n\n const query = new URLSearchParams(queryParameters);\n\n // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.\n if (!process.env.MSI_ENDPOINT) {\n throw new Error(`${msiName}: Missing environment variable: MSI_ENDPOINT`);\n }\n if (!process.env.MSI_SECRET) {\n throw new Error(`${msiName}: Missing environment variable: MSI_SECRET`);\n }\n\n return {\n url: `${process.env.MSI_ENDPOINT}?${query.toString()}`,\n method: \"GET\",\n headers: createHttpHeaders({\n Accept: \"application/json\",\n secret: process.env.MSI_SECRET\n })\n };\n}\n\nexport const appServiceMsi2017: MSI = {\n async isAvailable(scopes): Promise<boolean> {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);\n return false;\n }\n const env = process.env;\n const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);\n if (!result) {\n logger.info(\n `${msiName}: Unavailable. The environment variables needed are: MSI_ENDPOINT and MSI_SECRET.`\n );\n }\n return result;\n },\n async getToken(\n configuration: MSIConfiguration,\n getTokenOptions: GetTokenOptions = {}\n ): Promise<AccessToken | null> {\n const { identityClient, scopes, clientId } = configuration;\n\n logger.info(\n `${msiName}: Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`\n );\n\n return msiGenericGetToken(\n identityClient,\n prepareRequestOptions(scopes, clientId),\n expiresInParser,\n getTokenOptions\n );\n }\n};\n"]}
@@ -3,13 +3,18 @@
3
3
  import { createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline";
4
4
  import { readFile } from "fs";
5
5
  import { credentialLogger } from "../../util/logging";
6
- import { msiGenericGetToken } from "./utils";
6
+ import { mapScopesToResource, msiGenericGetToken } from "./utils";
7
7
  import { azureArcAPIVersion } from "./constants";
8
8
  import { AuthenticationError } from "../../client/errors";
9
- const logger = credentialLogger("ManagedIdentityCredential - ArcMSI");
9
+ const msiName = "ManagedIdentityCredential - Azure Arc MSI";
10
+ const logger = credentialLogger(msiName);
10
11
  // Azure Arc MSI doesn't have a special expiresIn parser.
11
12
  const expiresInParser = undefined;
12
- function prepareRequestOptions(resource) {
13
+ function prepareRequestOptions(scopes) {
14
+ const resource = mapScopesToResource(scopes);
15
+ if (!resource) {
16
+ throw new Error(`${msiName}: Multiple scopes are not supported.`);
17
+ }
13
18
  const queryParameters = {
14
19
  resource,
15
20
  "api-version": azureArcAPIVersion
@@ -17,7 +22,7 @@ function prepareRequestOptions(resource) {
17
22
  const query = new URLSearchParams(queryParameters);
18
23
  // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
19
24
  if (!process.env.IDENTITY_ENDPOINT) {
20
- throw new Error("Missing environment variable: IDENTITY_ENDPOINT");
25
+ throw new Error(`${msiName}: Missing environment variable: IDENTITY_ENDPOINT`);
21
26
  }
22
27
  return createPipelineRequest({
23
28
  // Should be similar to: http://localhost:40342/metadata/identity/oauth2/token
@@ -45,7 +50,7 @@ async function filePathRequest(identityClient, requestPrepareOptions) {
45
50
  if (response.bodyAsText) {
46
51
  message = ` Response: ${response.bodyAsText}`;
47
52
  }
48
- throw new AuthenticationError(response.status, `To authenticate with Azure Arc MSI, status code 401 is expected on the first request.${message}`);
53
+ throw new AuthenticationError(response.status, `${msiName}: To authenticate with Azure Arc MSI, status code 401 is expected on the first request. ${message}`);
49
54
  }
50
55
  const authHeader = response.headers.get("www-authenticate") || "";
51
56
  try {
@@ -56,23 +61,29 @@ async function filePathRequest(identityClient, requestPrepareOptions) {
56
61
  }
57
62
  }
58
63
  export const arcMsi = {
59
- async isAvailable() {
64
+ async isAvailable(scopes) {
65
+ const resource = mapScopesToResource(scopes);
66
+ if (!resource) {
67
+ logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
68
+ return false;
69
+ }
60
70
  const result = Boolean(process.env.IMDS_ENDPOINT && process.env.IDENTITY_ENDPOINT);
61
71
  if (!result) {
62
- logger.info("The Azure Arc MSI is unavailable.");
72
+ logger.info(`${msiName}: The environment variables needed are: IMDS_ENDPOINT and IDENTITY_ENDPOINT`);
63
73
  }
64
74
  return result;
65
75
  },
66
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
76
+ async getToken(configuration, getTokenOptions = {}) {
67
77
  var _a;
68
- logger.info(`Using the Azure Arc MSI to authenticate.`);
78
+ const { identityClient, scopes, clientId } = configuration;
79
+ logger.info(`${msiName}: Authenticating.`);
69
80
  if (clientId) {
70
- throw new Error("User assigned identity is not supported by the Azure Arc Managed Identity Endpoint. To authenticate with the system assigned identity omit the client id when constructing the ManagedIdentityCredential, or if authenticating with the DefaultAzureCredential ensure the AZURE_CLIENT_ID environment variable is not set.");
81
+ throw new Error(`${msiName}: User assigned identity is not supported by the Azure Arc Managed Identity Endpoint. To authenticate with the system assigned identity, omit the client id when constructing the ManagedIdentityCredential, or if authenticating with the DefaultAzureCredential ensure the AZURE_CLIENT_ID environment variable is not set.`);
71
82
  }
72
- const requestOptions = Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal, spanOptions: getTokenOptions.tracingOptions && getTokenOptions.tracingOptions.spanOptions }, prepareRequestOptions(resource));
83
+ const requestOptions = Object.assign(Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions(scopes)), { allowInsecureConnection: true });
73
84
  const filePath = await filePathRequest(identityClient, requestOptions);
74
85
  if (!filePath) {
75
- throw new Error("Azure Arc MSI failed to find the token file.");
86
+ throw new Error(`${msiName}: Failed to find the token file.`);
76
87
  }
77
88
  const key = await readFileAsync(filePath, { encoding: "utf-8" });
78
89
  (_a = requestOptions.headers) === null || _a === void 0 ? void 0 : _a.set("Authorization", `Basic ${key}`);
@@ -1 +1 @@
1
- {"version":3,"file":"arcMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/arcMsi.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport {\n createHttpHeaders,\n createPipelineRequest,\n PipelineRequestOptions\n} from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { readFile } from \"fs\";\nimport { MSI } from \"./models\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { IdentityClient } from \"../../client/identityClient\";\nimport { msiGenericGetToken } from \"./utils\";\nimport { azureArcAPIVersion } from \"./constants\";\nimport { AuthenticationError } from \"../../client/errors\";\n\nconst logger = credentialLogger(\"ManagedIdentityCredential - ArcMSI\");\n\n// Azure Arc MSI doesn't have a special expiresIn parser.\nconst expiresInParser = undefined;\n\nfunction prepareRequestOptions(resource?: string): PipelineRequestOptions {\n const queryParameters: any = {\n resource,\n \"api-version\": azureArcAPIVersion\n };\n\n const query = new URLSearchParams(queryParameters);\n\n // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.\n if (!process.env.IDENTITY_ENDPOINT) {\n throw new Error(\"Missing environment variable: IDENTITY_ENDPOINT\");\n }\n\n return createPipelineRequest({\n // Should be similar to: http://localhost:40342/metadata/identity/oauth2/token\n url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,\n method: \"GET\",\n headers: createHttpHeaders({\n Accept: \"application/json\",\n Metadata: \"true\"\n })\n });\n}\n\n// Since \"fs\"'s readFileSync locks the thread, and to avoid extra dependencies.\nfunction readFileAsync(path: string, options: { encoding: string }): Promise<string> {\n return new Promise((resolve, reject) =>\n readFile(path, options, (err, data) => {\n if (err) {\n reject(err);\n }\n resolve(data);\n })\n );\n}\n\nasync function filePathRequest(\n identityClient: IdentityClient,\n requestPrepareOptions: PipelineRequestOptions\n): Promise<string | undefined> {\n const response = await identityClient.sendRequest(createPipelineRequest(requestPrepareOptions));\n\n if (response.status !== 401) {\n let message = \"\";\n if (response.bodyAsText) {\n message = ` Response: ${response.bodyAsText}`;\n }\n throw new AuthenticationError(\n response.status,\n `To authenticate with Azure Arc MSI, status code 401 is expected on the first request.${message}`\n );\n }\n\n const authHeader = response.headers.get(\"www-authenticate\") || \"\";\n try {\n return authHeader.split(\"=\").slice(1)[0];\n } catch (e) {\n throw Error(`Invalid www-authenticate header format: ${authHeader}`);\n }\n}\n\nexport const arcMsi: MSI = {\n async isAvailable(): Promise<boolean> {\n const result = Boolean(process.env.IMDS_ENDPOINT && process.env.IDENTITY_ENDPOINT);\n if (!result) {\n logger.info(\"The Azure Arc MSI is unavailable.\");\n }\n return result;\n },\n async getToken(\n identityClient: IdentityClient,\n resource?: string,\n clientId?: string,\n getTokenOptions: GetTokenOptions = {}\n ): Promise<AccessToken | null> {\n logger.info(`Using the Azure Arc MSI to authenticate.`);\n\n if (clientId) {\n throw new Error(\n \"User assigned identity is not supported by the Azure Arc Managed Identity Endpoint. To authenticate with the system assigned identity omit the client id when constructing the ManagedIdentityCredential, or if authenticating with the DefaultAzureCredential ensure the AZURE_CLIENT_ID environment variable is not set.\"\n );\n }\n\n const requestOptions = {\n disableJsonStringifyOnBody: true,\n deserializationMapper: undefined,\n abortSignal: getTokenOptions.abortSignal,\n spanOptions: getTokenOptions.tracingOptions && getTokenOptions.tracingOptions.spanOptions,\n ...prepareRequestOptions(resource)\n };\n\n const filePath = await filePathRequest(identityClient, requestOptions);\n\n if (!filePath) {\n throw new Error(\"Azure Arc MSI failed to find the token file.\");\n }\n\n const key = await readFileAsync(filePath, { encoding: \"utf-8\" });\n requestOptions.headers?.set(\"Authorization\", `Basic ${key}`);\n\n return msiGenericGetToken(identityClient, requestOptions, expiresInParser, getTokenOptions);\n }\n};\n"]}
1
+ {"version":3,"file":"arcMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/arcMsi.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport {\n createHttpHeaders,\n createPipelineRequest,\n PipelineRequestOptions\n} from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { readFile } from \"fs\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { IdentityClient } from \"../../client/identityClient\";\nimport { mapScopesToResource, msiGenericGetToken } from \"./utils\";\nimport { azureArcAPIVersion } from \"./constants\";\nimport { AuthenticationError } from \"../../client/errors\";\n\nconst msiName = \"ManagedIdentityCredential - Azure Arc MSI\";\nconst logger = credentialLogger(msiName);\n\n// Azure Arc MSI doesn't have a special expiresIn parser.\nconst expiresInParser = undefined;\n\nfunction prepareRequestOptions(scopes: string | string[]): PipelineRequestOptions {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n throw new Error(`${msiName}: Multiple scopes are not supported.`);\n }\n const queryParameters: any = {\n resource,\n \"api-version\": azureArcAPIVersion\n };\n\n const query = new URLSearchParams(queryParameters);\n\n // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.\n if (!process.env.IDENTITY_ENDPOINT) {\n throw new Error(`${msiName}: Missing environment variable: IDENTITY_ENDPOINT`);\n }\n\n return createPipelineRequest({\n // Should be similar to: http://localhost:40342/metadata/identity/oauth2/token\n url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,\n method: \"GET\",\n headers: createHttpHeaders({\n Accept: \"application/json\",\n Metadata: \"true\"\n })\n });\n}\n\n// Since \"fs\"'s readFileSync locks the thread, and to avoid extra dependencies.\nfunction readFileAsync(path: string, options: { encoding: string }): Promise<string> {\n return new Promise((resolve, reject) =>\n readFile(path, options, (err, data) => {\n if (err) {\n reject(err);\n }\n resolve(data);\n })\n );\n}\n\nasync function filePathRequest(\n identityClient: IdentityClient,\n requestPrepareOptions: PipelineRequestOptions\n): Promise<string | undefined> {\n const response = await identityClient.sendRequest(createPipelineRequest(requestPrepareOptions));\n\n if (response.status !== 401) {\n let message = \"\";\n if (response.bodyAsText) {\n message = ` Response: ${response.bodyAsText}`;\n }\n throw new AuthenticationError(\n response.status,\n `${msiName}: To authenticate with Azure Arc MSI, status code 401 is expected on the first request. ${message}`\n );\n }\n\n const authHeader = response.headers.get(\"www-authenticate\") || \"\";\n try {\n return authHeader.split(\"=\").slice(1)[0];\n } catch (e) {\n throw Error(`Invalid www-authenticate header format: ${authHeader}`);\n }\n}\n\nexport const arcMsi: MSI = {\n async isAvailable(scopes): Promise<boolean> {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);\n return false;\n }\n const result = Boolean(process.env.IMDS_ENDPOINT && process.env.IDENTITY_ENDPOINT);\n if (!result) {\n logger.info(\n `${msiName}: The environment variables needed are: IMDS_ENDPOINT and IDENTITY_ENDPOINT`\n );\n }\n return result;\n },\n async getToken(\n configuration: MSIConfiguration,\n getTokenOptions: GetTokenOptions = {}\n ): Promise<AccessToken | null> {\n const { identityClient, scopes, clientId } = configuration;\n\n logger.info(`${msiName}: Authenticating.`);\n\n if (clientId) {\n throw new Error(\n `${msiName}: User assigned identity is not supported by the Azure Arc Managed Identity Endpoint. To authenticate with the system assigned identity, omit the client id when constructing the ManagedIdentityCredential, or if authenticating with the DefaultAzureCredential ensure the AZURE_CLIENT_ID environment variable is not set.`\n );\n }\n\n const requestOptions = {\n disableJsonStringifyOnBody: true,\n deserializationMapper: undefined,\n abortSignal: getTokenOptions.abortSignal,\n ...prepareRequestOptions(scopes),\n allowInsecureConnection: true\n };\n\n const filePath = await filePathRequest(identityClient, requestOptions);\n\n if (!filePath) {\n throw new Error(`${msiName}: Failed to find the token file.`);\n }\n\n const key = await readFileAsync(filePath, { encoding: \"utf-8\" });\n requestOptions.headers?.set(\"Authorization\", `Basic ${key}`);\n\n return msiGenericGetToken(identityClient, requestOptions, expiresInParser, getTokenOptions);\n }\n};\n"]}
@@ -1,13 +1,17 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT license.
3
- import qs from "qs";
4
3
  import { createHttpHeaders } from "@azure/core-rest-pipeline";
5
4
  import { credentialLogger } from "../../util/logging";
6
- import { msiGenericGetToken } from "./utils";
7
- const logger = credentialLogger("ManagedIdentityCredential - CloudShellMSI");
5
+ import { mapScopesToResource, msiGenericGetToken } from "./utils";
6
+ const msiName = "ManagedIdentityCredential - CloudShellMSI";
7
+ const logger = credentialLogger(msiName);
8
8
  // Cloud Shell MSI doesn't have a special expiresIn parser.
9
9
  const expiresInParser = undefined;
10
- function prepareRequestOptions(resource, clientId) {
10
+ function prepareRequestOptions(scopes, clientId) {
11
+ const resource = mapScopesToResource(scopes);
12
+ if (!resource) {
13
+ throw new Error(`${msiName}: Multiple scopes are not supported.`);
14
+ }
11
15
  const body = {
12
16
  resource
13
17
  };
@@ -16,12 +20,13 @@ function prepareRequestOptions(resource, clientId) {
16
20
  }
17
21
  // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
18
22
  if (!process.env.MSI_ENDPOINT) {
19
- throw new Error("Missing environment variable: MSI_ENDPOINT");
23
+ throw new Error(`${msiName}: Missing environment variable: MSI_ENDPOINT`);
20
24
  }
25
+ const params = new URLSearchParams(body);
21
26
  return {
22
27
  url: process.env.MSI_ENDPOINT,
23
28
  method: "POST",
24
- body: qs.stringify(body),
29
+ body: params.toString(),
25
30
  headers: createHttpHeaders({
26
31
  Accept: "application/json",
27
32
  Metadata: "true",
@@ -30,16 +35,22 @@ function prepareRequestOptions(resource, clientId) {
30
35
  };
31
36
  }
32
37
  export const cloudShellMsi = {
33
- async isAvailable() {
38
+ async isAvailable(scopes) {
39
+ const resource = mapScopesToResource(scopes);
40
+ if (!resource) {
41
+ logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
42
+ return false;
43
+ }
34
44
  const result = Boolean(process.env.MSI_ENDPOINT);
35
45
  if (!result) {
36
- logger.info("The Azure Cloud Shell MSI is unavailable.");
46
+ logger.info(`${msiName}: Unavailable. The environment variable MSI_ENDPOINT is needed.`);
37
47
  }
38
48
  return result;
39
49
  },
40
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
41
- logger.info(`Using the endpoint coming form the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the Cloud Shell to proceed with the authentication.`);
42
- return msiGenericGetToken(identityClient, prepareRequestOptions(resource, clientId), expiresInParser, getTokenOptions);
50
+ async getToken(configuration, getTokenOptions = {}) {
51
+ const { identityClient, scopes, clientId } = configuration;
52
+ logger.info(`${msiName}: Using the endpoint coming form the environment variable MSI_ENDPOINT = ${process.env.MSI_ENDPOINT}.`);
53
+ return msiGenericGetToken(identityClient, prepareRequestOptions(scopes, clientId), expiresInParser, getTokenOptions);
43
54
  }
44
55
  };
45
56
  //# sourceMappingURL=cloudShellMsi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cloudShellMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/cloudShellMsi.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAA0B,MAAM,2BAA2B,CAAC;AAGtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE7C,MAAM,MAAM,GAAG,gBAAgB,CAAC,2CAA2C,CAAC,CAAC;AAE7E,2DAA2D;AAC3D,MAAM,eAAe,GAAG,SAAS,CAAC;AAElC,SAAS,qBAAqB,CAAC,QAAgB,EAAE,QAAiB;IAChE,MAAM,IAAI,GAAQ;QAChB,QAAQ;KACT,CAAC;IAEF,IAAI,QAAQ,EAAE;QACZ,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;KAC3B;IAED,wIAAwI;IACxI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE;QAC7B,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;KAC/D;IAED,OAAO;QACL,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QAC7B,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC;QACxB,OAAO,EAAE,iBAAiB,CAAC;YACzB,MAAM,EAAE,kBAAkB;YAC1B,QAAQ,EAAE,MAAM;YAChB,cAAc,EAAE,mCAAmC;SACpD,CAAC;KACH,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAQ;IAChC,KAAK,CAAC,WAAW;QACf,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACjD,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;SAC1D;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,KAAK,CAAC,QAAQ,CACZ,cAA8B,EAC9B,QAAgB,EAChB,QAAiB,EACjB,kBAAmC,EAAE;QAErC,MAAM,CAAC,IAAI,CACT,wEAAwE,OAAO,CAAC,GAAG,CAAC,YAAY,iEAAiE,CAClK,CAAC;QAEF,OAAO,kBAAkB,CACvB,cAAc,EACd,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,CAAC,EACzC,eAAe,EACf,eAAe,CAChB,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport qs from \"qs\";\n\nimport { createHttpHeaders, PipelineRequestOptions } from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { MSI } from \"./models\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { IdentityClient } from \"../../client/identityClient\";\nimport { msiGenericGetToken } from \"./utils\";\n\nconst logger = credentialLogger(\"ManagedIdentityCredential - CloudShellMSI\");\n\n// Cloud Shell MSI doesn't have a special expiresIn parser.\nconst expiresInParser = undefined;\n\nfunction prepareRequestOptions(resource: string, clientId?: string): PipelineRequestOptions {\n const body: any = {\n resource\n };\n\n if (clientId) {\n body.client_id = clientId;\n }\n\n // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.\n if (!process.env.MSI_ENDPOINT) {\n throw new Error(\"Missing environment variable: MSI_ENDPOINT\");\n }\n\n return {\n url: process.env.MSI_ENDPOINT,\n method: \"POST\",\n body: qs.stringify(body),\n headers: createHttpHeaders({\n Accept: \"application/json\",\n Metadata: \"true\",\n \"Content-Type\": \"application/x-www-form-urlencoded\"\n })\n };\n}\n\nexport const cloudShellMsi: MSI = {\n async isAvailable(): Promise<boolean> {\n const result = Boolean(process.env.MSI_ENDPOINT);\n if (!result) {\n logger.info(\"The Azure Cloud Shell MSI is unavailable.\");\n }\n return result;\n },\n async getToken(\n identityClient: IdentityClient,\n resource: string,\n clientId?: string,\n getTokenOptions: GetTokenOptions = {}\n ): Promise<AccessToken | null> {\n logger.info(\n `Using the endpoint coming form the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the Cloud Shell to proceed with the authentication.`\n );\n\n return msiGenericGetToken(\n identityClient,\n prepareRequestOptions(resource, clientId),\n expiresInParser,\n getTokenOptions\n );\n }\n};\n"]}
1
+ {"version":3,"file":"cloudShellMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/cloudShellMsi.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,iBAAiB,EAA0B,MAAM,2BAA2B,CAAC;AAGtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElE,MAAM,OAAO,GAAG,2CAA2C,CAAC;AAC5D,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAEzC,2DAA2D;AAC3D,MAAM,eAAe,GAAG,SAAS,CAAC;AAElC,SAAS,qBAAqB,CAC5B,MAAyB,EACzB,QAAiB;IAEjB,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,CAAC,QAAQ,EAAE;QACb,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,sCAAsC,CAAC,CAAC;KACnE;IAED,MAAM,IAAI,GAAQ;QAChB,QAAQ;KACT,CAAC;IAEF,IAAI,QAAQ,EAAE;QACZ,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;KAC3B;IAED,wIAAwI;IACxI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE;QAC7B,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,8CAA8C,CAAC,CAAC;KAC3E;IACD,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;IACzC,OAAO;QACL,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QAC7B,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE;QACvB,OAAO,EAAE,iBAAiB,CAAC;YACzB,MAAM,EAAE,kBAAkB;YAC1B,QAAQ,EAAE,MAAM;YAChB,cAAc,EAAE,mCAAmC;SACpD,CAAC;KACH,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAQ;IAChC,KAAK,CAAC,WAAW,CAAC,MAAM;QACtB,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,EAAE;YACb,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,mDAAmD,CAAC,CAAC;YAC3E,OAAO,KAAK,CAAC;SACd;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACjD,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,iEAAiE,CAAC,CAAC;SAC1F;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,KAAK,CAAC,QAAQ,CACZ,aAA+B,EAC/B,kBAAmC,EAAE;QAErC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC;QAE3D,MAAM,CAAC,IAAI,CACT,GAAG,OAAO,4EAA4E,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,CAClH,CAAC;QAEF,OAAO,kBAAkB,CACvB,cAAc,EACd,qBAAqB,CAAC,MAAM,EAAE,QAAQ,CAAC,EACvC,eAAe,EACf,eAAe,CAChB,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { createHttpHeaders, PipelineRequestOptions } from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { mapScopesToResource, msiGenericGetToken } from \"./utils\";\n\nconst msiName = \"ManagedIdentityCredential - CloudShellMSI\";\nconst logger = credentialLogger(msiName);\n\n// Cloud Shell MSI doesn't have a special expiresIn parser.\nconst expiresInParser = undefined;\n\nfunction prepareRequestOptions(\n scopes: string | string[],\n clientId?: string\n): PipelineRequestOptions {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n throw new Error(`${msiName}: Multiple scopes are not supported.`);\n }\n\n const body: any = {\n resource\n };\n\n if (clientId) {\n body.client_id = clientId;\n }\n\n // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.\n if (!process.env.MSI_ENDPOINT) {\n throw new Error(`${msiName}: Missing environment variable: MSI_ENDPOINT`);\n }\n const params = new URLSearchParams(body);\n return {\n url: process.env.MSI_ENDPOINT,\n method: \"POST\",\n body: params.toString(),\n headers: createHttpHeaders({\n Accept: \"application/json\",\n Metadata: \"true\",\n \"Content-Type\": \"application/x-www-form-urlencoded\"\n })\n };\n}\n\nexport const cloudShellMsi: MSI = {\n async isAvailable(scopes): Promise<boolean> {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);\n return false;\n }\n const result = Boolean(process.env.MSI_ENDPOINT);\n if (!result) {\n logger.info(`${msiName}: Unavailable. The environment variable MSI_ENDPOINT is needed.`);\n }\n return result;\n },\n async getToken(\n configuration: MSIConfiguration,\n getTokenOptions: GetTokenOptions = {}\n ): Promise<AccessToken | null> {\n const { identityClient, scopes, clientId } = configuration;\n\n logger.info(\n `${msiName}: Using the endpoint coming form the environment variable MSI_ENDPOINT = ${process.env.MSI_ENDPOINT}.`\n );\n\n return msiGenericGetToken(\n identityClient,\n prepareRequestOptions(scopes, clientId),\n expiresInParser,\n getTokenOptions\n );\n }\n};\n"]}
@@ -2,14 +2,19 @@
2
2
  // Licensed under the MIT license.
3
3
  import { createHttpHeaders } from "@azure/core-rest-pipeline";
4
4
  import { credentialLogger } from "../../util/logging";
5
- import { msiGenericGetToken } from "./utils";
5
+ import { mapScopesToResource, msiGenericGetToken } from "./utils";
6
6
  import { azureFabricVersion } from "./constants";
7
- const logger = credentialLogger("ManagedIdentityCredential - Fabric MSI");
7
+ const msiName = "ManagedIdentityCredential - Fabric MSI";
8
+ const logger = credentialLogger(msiName);
8
9
  function expiresInParser(requestBody) {
9
10
  // Parses a string representation of the seconds since epoch into a number value
10
11
  return Number(requestBody.expires_on);
11
12
  }
12
- function prepareRequestOptions(resource, clientId) {
13
+ function prepareRequestOptions(scopes, clientId) {
14
+ const resource = mapScopesToResource(scopes);
15
+ if (!resource) {
16
+ throw new Error(`${msiName}: Multiple scopes are not supported.`);
17
+ }
13
18
  const queryParameters = {
14
19
  resource,
15
20
  "api-version": azureFabricVersion
@@ -45,22 +50,29 @@ function prepareRequestOptions(resource, clientId) {
45
50
  // curl --insecure $IDENTITY_ENDPOINT'?api-version=2019-07-01-preview&resource=https://vault.azure.net/' -H "Secret: $IDENTITY_HEADER"
46
51
  //
47
52
  export const fabricMsi = {
48
- async isAvailable() {
53
+ async isAvailable(scopes) {
54
+ const resource = mapScopesToResource(scopes);
55
+ if (!resource) {
56
+ logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
57
+ return false;
58
+ }
49
59
  const env = process.env;
50
60
  const result = Boolean(env.IDENTITY_ENDPOINT && env.IDENTITY_HEADER && env.IDENTITY_SERVER_THUMBPRINT);
51
61
  if (!result) {
52
- logger.info("The Azure App Service Fabric MSI is unavailable.");
62
+ logger.info(`${msiName}: Unavailable. The environment variables needed are: IDENTITY_ENDPOINT, IDENTITY_HEADER and IDENTITY_SERVER_THUMBPRINT`);
53
63
  }
54
64
  return result;
55
65
  },
56
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
66
+ async getToken(configuration, getTokenOptions = {}) {
67
+ const { identityClient, scopes, clientId } = configuration;
57
68
  logger.info([
69
+ `${msiName}:`,
58
70
  "Using the endpoint and the secret coming from the environment variables:",
59
71
  `IDENTITY_ENDPOINT=${process.env.IDENTITY_ENDPOINT},`,
60
72
  "IDENTITY_HEADER=[REDACTED] and",
61
73
  "IDENTITY_SERVER_THUMBPRINT=[REDACTED]."
62
74
  ].join(" "));
63
- return msiGenericGetToken(identityClient, prepareRequestOptions(resource, clientId), expiresInParser, getTokenOptions);
75
+ return msiGenericGetToken(identityClient, prepareRequestOptions(scopes, clientId), expiresInParser, getTokenOptions);
64
76
  }
65
77
  };
66
78
  //# sourceMappingURL=fabricMsi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fabricMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/fabricMsi.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,iBAAiB,EAA0B,MAAM,2BAA2B,CAAC;AAGtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,MAAM,GAAG,gBAAgB,CAAC,wCAAwC,CAAC,CAAC;AAE1E,SAAS,eAAe,CAAC,WAAgB;IACvC,gFAAgF;IAChF,OAAO,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,qBAAqB,CAAC,QAAgB,EAAE,QAAiB;IAChE,MAAM,eAAe,GAAQ;QAC3B,QAAQ;QACR,aAAa,EAAE,kBAAkB;KAClC,CAAC;IAEF,IAAI,QAAQ,EAAE;QACZ,eAAe,CAAC,SAAS,GAAG,QAAQ,CAAC;KACtC;IAED,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,eAAe,CAAC,CAAC;IAEnD,wIAAwI;IACxI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE;QAClC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;KACpE;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE;QAChC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;KAClE;IAED,OAAO;QACL,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAE;QAC3D,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,iBAAiB,CAAC;YACzB,MAAM,EAAE,kBAAkB;YAC1B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe;SACpC,CAAC;KACH,CAAC;AACJ,CAAC;AAED,6GAA6G;AAC7G,EAAE;AACF,iBAAiB;AACjB,2CAA2C;AAC3C,4BAA4B;AAC5B,EAAE;AACF,kCAAkC;AAClC,EAAE;AACF,wIAAwI;AACxI,EAAE;AAEF,MAAM,CAAC,MAAM,SAAS,GAAQ;IAC5B,KAAK,CAAC,WAAW;QACf,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;QACxB,MAAM,MAAM,GAAG,OAAO,CACpB,GAAG,CAAC,iBAAiB,IAAI,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC,0BAA0B,CAC/E,CAAC;QACF,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;SACjE;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,KAAK,CAAC,QAAQ,CACZ,cAA8B,EAC9B,QAAgB,EAChB,QAAiB,EACjB,kBAAmC,EAAE;QAErC,MAAM,CAAC,IAAI,CACT;YACE,0EAA0E;YAC1E,qBAAqB,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG;YACrD,gCAAgC;YAChC,wCAAwC;SACzC,CAAC,IAAI,CAAC,GAAG,CAAC,CACZ,CAAC;QAEF,OAAO,kBAAkB,CACvB,cAAc,EACd,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,CAAC,EACzC,eAAe,EACf,eAAe,CAChB,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { createHttpHeaders, PipelineRequestOptions } from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { MSI } from \"./models\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { IdentityClient } from \"../../client/identityClient\";\nimport { msiGenericGetToken } from \"./utils\";\nimport { azureFabricVersion } from \"./constants\";\n\nconst logger = credentialLogger(\"ManagedIdentityCredential - Fabric MSI\");\n\nfunction expiresInParser(requestBody: any): number {\n // Parses a string representation of the seconds since epoch into a number value\n return Number(requestBody.expires_on);\n}\n\nfunction prepareRequestOptions(resource: string, clientId?: string): PipelineRequestOptions {\n const queryParameters: any = {\n resource,\n \"api-version\": azureFabricVersion\n };\n\n if (clientId) {\n queryParameters.client_id = clientId;\n }\n\n const query = new URLSearchParams(queryParameters);\n\n // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.\n if (!process.env.IDENTITY_ENDPOINT) {\n throw new Error(\"Missing environment variable: IDENTITY_ENDPOINT\");\n }\n if (!process.env.IDENTITY_HEADER) {\n throw new Error(\"Missing environment variable: IDENTITY_HEADER\");\n }\n\n return {\n url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,\n method: \"GET\",\n headers: createHttpHeaders({\n Accept: \"application/json\",\n Secret: process.env.IDENTITY_HEADER\n })\n };\n}\n\n// This credential can be easily tested by deploying a container to Azure Service Fabric with the Dockerfile:\n//\n// FROM node:12\n// RUN wget https://host.any/path/bash.sh\n// CMD [\"bash\", \"bash.sh\"]\n//\n// Where the bash script contains:\n//\n// curl --insecure $IDENTITY_ENDPOINT'?api-version=2019-07-01-preview&resource=https://vault.azure.net/' -H \"Secret: $IDENTITY_HEADER\"\n//\n\nexport const fabricMsi: MSI = {\n async isAvailable(): Promise<boolean> {\n const env = process.env;\n const result = Boolean(\n env.IDENTITY_ENDPOINT && env.IDENTITY_HEADER && env.IDENTITY_SERVER_THUMBPRINT\n );\n if (!result) {\n logger.info(\"The Azure App Service Fabric MSI is unavailable.\");\n }\n return result;\n },\n async getToken(\n identityClient: IdentityClient,\n resource: string,\n clientId?: string,\n getTokenOptions: GetTokenOptions = {}\n ): Promise<AccessToken | null> {\n logger.info(\n [\n \"Using the endpoint and the secret coming from the environment variables:\",\n `IDENTITY_ENDPOINT=${process.env.IDENTITY_ENDPOINT},`,\n \"IDENTITY_HEADER=[REDACTED] and\",\n \"IDENTITY_SERVER_THUMBPRINT=[REDACTED].\"\n ].join(\" \")\n );\n\n return msiGenericGetToken(\n identityClient,\n prepareRequestOptions(resource, clientId),\n expiresInParser,\n getTokenOptions\n );\n }\n};\n"]}
1
+ {"version":3,"file":"fabricMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/fabricMsi.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { createHttpHeaders, PipelineRequestOptions } from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { mapScopesToResource, msiGenericGetToken } from \"./utils\";\nimport { azureFabricVersion } from \"./constants\";\n\nconst msiName = \"ManagedIdentityCredential - Fabric MSI\";\nconst logger = credentialLogger(msiName);\n\nfunction expiresInParser(requestBody: any): number {\n // Parses a string representation of the seconds since epoch into a number value\n return Number(requestBody.expires_on);\n}\n\nfunction prepareRequestOptions(\n scopes: string | string[],\n clientId?: string\n): PipelineRequestOptions {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n throw new Error(`${msiName}: Multiple scopes are not supported.`);\n }\n\n const queryParameters: any = {\n resource,\n \"api-version\": azureFabricVersion\n };\n\n if (clientId) {\n queryParameters.client_id = clientId;\n }\n\n const query = new URLSearchParams(queryParameters);\n\n // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.\n if (!process.env.IDENTITY_ENDPOINT) {\n throw new Error(\"Missing environment variable: IDENTITY_ENDPOINT\");\n }\n if (!process.env.IDENTITY_HEADER) {\n throw new Error(\"Missing environment variable: IDENTITY_HEADER\");\n }\n\n return {\n url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,\n method: \"GET\",\n headers: createHttpHeaders({\n Accept: \"application/json\",\n Secret: process.env.IDENTITY_HEADER\n })\n };\n}\n\n// This credential can be easily tested by deploying a container to Azure Service Fabric with the Dockerfile:\n//\n// FROM node:12\n// RUN wget https://host.any/path/bash.sh\n// CMD [\"bash\", \"bash.sh\"]\n//\n// Where the bash script contains:\n//\n// curl --insecure $IDENTITY_ENDPOINT'?api-version=2019-07-01-preview&resource=https://vault.azure.net/' -H \"Secret: $IDENTITY_HEADER\"\n//\n\nexport const fabricMsi: MSI = {\n async isAvailable(scopes): Promise<boolean> {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);\n return false;\n }\n const env = process.env;\n const result = Boolean(\n env.IDENTITY_ENDPOINT && env.IDENTITY_HEADER && env.IDENTITY_SERVER_THUMBPRINT\n );\n if (!result) {\n logger.info(\n `${msiName}: Unavailable. The environment variables needed are: IDENTITY_ENDPOINT, IDENTITY_HEADER and IDENTITY_SERVER_THUMBPRINT`\n );\n }\n return result;\n },\n async getToken(\n configuration: MSIConfiguration,\n getTokenOptions: GetTokenOptions = {}\n ): Promise<AccessToken | null> {\n const { identityClient, scopes, clientId } = configuration;\n\n logger.info(\n [\n `${msiName}:`,\n \"Using the endpoint and the secret coming from the environment variables:\",\n `IDENTITY_ENDPOINT=${process.env.IDENTITY_ENDPOINT},`,\n \"IDENTITY_HEADER=[REDACTED] and\",\n \"IDENTITY_SERVER_THUMBPRINT=[REDACTED].\"\n ].join(\" \")\n );\n\n return msiGenericGetToken(\n identityClient,\n prepareRequestOptions(scopes, clientId),\n expiresInParser,\n getTokenOptions\n );\n }\n};\n"]}
@@ -1,31 +1,35 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT license.
3
- import qs from "qs";
4
3
  import { delay } from "@azure/core-util";
5
4
  import { createHttpHeaders, createPipelineRequest, RestError } from "@azure/core-rest-pipeline";
6
5
  import { SpanStatusCode } from "@azure/core-tracing";
7
6
  import { credentialLogger } from "../../util/logging";
8
7
  import { createSpan } from "../../util/tracing";
9
8
  import { imdsApiVersion, imdsEndpointPath, imdsHost } from "./constants";
10
- import { msiGenericGetToken } from "./utils";
9
+ import { mapScopesToResource, msiGenericGetToken } from "./utils";
11
10
  import { AuthenticationError } from "../../client/errors";
12
- const logger = credentialLogger("ManagedIdentityCredential - IMDS");
11
+ const msiName = "ManagedIdentityCredential - IMDS";
12
+ const logger = credentialLogger(msiName);
13
13
  function expiresInParser(requestBody) {
14
14
  if (requestBody.expires_on) {
15
15
  // Use the expires_on timestamp if it's available
16
16
  const expires = +requestBody.expires_on * 1000;
17
- logger.info(`IMDS using expires_on: ${expires} (original value: ${requestBody.expires_on})`);
17
+ logger.info(`${msiName}: IMDS using expires_on: ${expires} (original value: ${requestBody.expires_on})`);
18
18
  return expires;
19
19
  }
20
20
  else {
21
21
  // If these aren't possible, use expires_in and calculate a timestamp
22
22
  const expires = Date.now() + requestBody.expires_in * 1000;
23
- logger.info(`IMDS using expires_in: ${expires} (original value: ${requestBody.expires_in})`);
23
+ logger.info(`${msiName}: IMDS using expires_in: ${expires} (original value: ${requestBody.expires_in})`);
24
24
  return expires;
25
25
  }
26
26
  }
27
- function prepareRequestOptions(resource, clientId) {
27
+ function prepareRequestOptions(scopes, clientId) {
28
28
  var _a;
29
+ const resource = mapScopesToResource(scopes);
30
+ if (!resource) {
31
+ throw new Error(`${msiName}: Multiple scopes are not supported.`);
32
+ }
29
33
  const queryParameters = {
30
34
  resource,
31
35
  "api-version": imdsApiVersion
@@ -33,7 +37,8 @@ function prepareRequestOptions(resource, clientId) {
33
37
  if (clientId) {
34
38
  queryParameters.client_id = clientId;
35
39
  }
36
- const query = qs.stringify(queryParameters);
40
+ const params = new URLSearchParams(queryParameters);
41
+ const query = params.toString();
37
42
  const url = new URL(imdsEndpointPath, (_a = process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) !== null && _a !== void 0 ? _a : imdsHost);
38
43
  return {
39
44
  url: `${url}?${query}`,
@@ -51,8 +56,13 @@ export const imdsMsiRetryConfig = {
51
56
  intervalIncrement: 2
52
57
  };
53
58
  export const imdsMsi = {
54
- async isAvailable(identityClient, resource, clientId, getTokenOptions) {
59
+ async isAvailable(scopes, identityClient, clientId, getTokenOptions) {
55
60
  var _a, _b;
61
+ const resource = mapScopesToResource(scopes);
62
+ if (!resource) {
63
+ logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
64
+ return false;
65
+ }
56
66
  const { span, updatedOptions: options } = createSpan("ManagedIdentityCredential-pingImdsEndpoint", getTokenOptions);
57
67
  // if the PodIdenityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist
58
68
  if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) {
@@ -65,10 +75,7 @@ export const imdsMsi = {
65
75
  // IMDS endpoint
66
76
  requestOptions.headers.delete("Metadata");
67
77
  }
68
- requestOptions.tracingOptions = {
69
- spanOptions: options.tracingOptions && options.tracingOptions.spanOptions,
70
- tracingContext: options.tracingOptions && options.tracingOptions.tracingContext
71
- };
78
+ requestOptions.tracingOptions = options.tracingOptions;
72
79
  try {
73
80
  // Create a request with a timeout since we expect that
74
81
  // not having a "Metadata" header should cause an error to be
@@ -78,18 +85,19 @@ export const imdsMsi = {
78
85
  // This MSI uses the imdsEndpoint to get the token, which only uses http://
79
86
  request.allowInsecureConnection = true;
80
87
  try {
81
- logger.info(`Pinging the Azure IMDS endpoint`);
88
+ logger.info(`${msiName}: Pinging the Azure IMDS endpoint`);
82
89
  await identityClient.sendRequest(request);
83
90
  }
84
91
  catch (err) {
85
92
  if ((err.name === "RestError" && err.code === RestError.REQUEST_SEND_ERROR) ||
86
93
  err.name === "AbortError" ||
94
+ err.code === "ENETUNREACH" || // Network unreachable
87
95
  err.code === "ECONNREFUSED" || // connection refused
88
96
  err.code === "EHOSTDOWN" // host is down
89
97
  ) {
90
98
  // If the request failed, or Node.js was unable to establish a connection,
91
99
  // or the host was down, we'll assume the IMDS endpoint isn't available.
92
- logger.info(`The Azure IMDS endpoint is unavailable`);
100
+ logger.info(`${msiName}: The Azure IMDS endpoint is unavailable`);
93
101
  span.setStatus({
94
102
  code: SpanStatusCode.ERROR,
95
103
  message: err.message
@@ -98,13 +106,13 @@ export const imdsMsi = {
98
106
  }
99
107
  }
100
108
  // If we received any response, the endpoint is available
101
- logger.info(`The Azure IMDS endpoint is available`);
109
+ logger.info(`${msiName}: The Azure IMDS endpoint is available`);
102
110
  return true;
103
111
  }
104
112
  catch (err) {
105
113
  // createWebResource failed.
106
114
  // This error should bubble up to the user.
107
- logger.info(`Error when creating the WebResource for the Azure IMDS endpoint: ${err.message}`);
115
+ logger.info(`${msiName}: Error when creating the WebResource for the Azure IMDS endpoint: ${err.message}`);
108
116
  span.setStatus({
109
117
  code: SpanStatusCode.ERROR,
110
118
  message: err.message
@@ -115,12 +123,13 @@ export const imdsMsi = {
115
123
  span.end();
116
124
  }
117
125
  },
118
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
119
- logger.info(`Using the Azure IMDS endpoint coming from the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the cloud shell to proceed with the authentication.`);
126
+ async getToken(configuration, getTokenOptions = {}) {
127
+ const { identityClient, scopes, clientId } = configuration;
128
+ logger.info(`${msiName}: Using the Azure IMDS endpoint coming from the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the cloud shell to proceed with the authentication.`);
120
129
  let nextDelayInMs = imdsMsiRetryConfig.startDelayInMs;
121
130
  for (let retries = 0; retries < imdsMsiRetryConfig.maxRetries; retries++) {
122
131
  try {
123
- return await msiGenericGetToken(identityClient, prepareRequestOptions(resource, clientId), expiresInParser, getTokenOptions);
132
+ return await msiGenericGetToken(identityClient, prepareRequestOptions(scopes, clientId), expiresInParser, getTokenOptions);
124
133
  }
125
134
  catch (error) {
126
135
  if (error.statusCode === 404) {
@@ -131,7 +140,7 @@ export const imdsMsi = {
131
140
  throw error;
132
141
  }
133
142
  }
134
- throw new AuthenticationError(404, `Failed to retrieve IMDS token after ${imdsMsiRetryConfig.maxRetries} retries.`);
143
+ throw new AuthenticationError(404, `${msiName}: Failed to retrieve IMDS token after ${imdsMsiRetryConfig.maxRetries} retries.`);
135
144
  }
136
145
  };
137
146
  //# sourceMappingURL=imdsMsi.js.map