@azure/identity 4.13.0-alpha.20251103.1 → 4.14.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/browser/constants.d.ts +1 -1
  2. package/dist/browser/constants.d.ts.map +1 -1
  3. package/dist/browser/constants.js +1 -1
  4. package/dist/browser/constants.js.map +1 -1
  5. package/dist/browser/credentials/workloadIdentityCredentialOptions.d.ts +4 -0
  6. package/dist/browser/credentials/workloadIdentityCredentialOptions.d.ts.map +1 -1
  7. package/dist/browser/credentials/workloadIdentityCredentialOptions.js.map +1 -1
  8. package/dist/browser/util/certificatesUtils.d.ts +13 -0
  9. package/dist/browser/util/certificatesUtils.d.ts.map +1 -0
  10. package/dist/browser/util/certificatesUtils.js +47 -0
  11. package/dist/browser/util/certificatesUtils.js.map +1 -0
  12. package/dist/commonjs/constants.d.ts +1 -1
  13. package/dist/commonjs/constants.d.ts.map +1 -1
  14. package/dist/commonjs/constants.js +1 -1
  15. package/dist/commonjs/constants.js.map +1 -1
  16. package/dist/commonjs/credentials/clientCertificateCredential.d.ts.map +1 -1
  17. package/dist/commonjs/credentials/clientCertificateCredential.js +2 -13
  18. package/dist/commonjs/credentials/clientCertificateCredential.js.map +1 -1
  19. package/dist/commonjs/credentials/workloadIdentityCredential.d.ts +20 -0
  20. package/dist/commonjs/credentials/workloadIdentityCredential.d.ts.map +1 -1
  21. package/dist/commonjs/credentials/workloadIdentityCredential.js +192 -14
  22. package/dist/commonjs/credentials/workloadIdentityCredential.js.map +1 -1
  23. package/dist/commonjs/credentials/workloadIdentityCredentialOptions.d.ts +4 -0
  24. package/dist/commonjs/credentials/workloadIdentityCredentialOptions.d.ts.map +1 -1
  25. package/dist/commonjs/credentials/workloadIdentityCredentialOptions.js.map +1 -1
  26. package/dist/commonjs/util/certificatesUtils.d.ts +13 -0
  27. package/dist/commonjs/util/certificatesUtils.d.ts.map +1 -0
  28. package/dist/commonjs/util/certificatesUtils.js +51 -0
  29. package/dist/commonjs/util/certificatesUtils.js.map +1 -0
  30. package/dist/esm/constants.d.ts +1 -1
  31. package/dist/esm/constants.d.ts.map +1 -1
  32. package/dist/esm/constants.js +1 -1
  33. package/dist/esm/constants.js.map +1 -1
  34. package/dist/esm/credentials/clientCertificateCredential.d.ts.map +1 -1
  35. package/dist/esm/credentials/clientCertificateCredential.js +2 -13
  36. package/dist/esm/credentials/clientCertificateCredential.js.map +1 -1
  37. package/dist/esm/credentials/workloadIdentityCredential.d.ts +20 -0
  38. package/dist/esm/credentials/workloadIdentityCredential.d.ts.map +1 -1
  39. package/dist/esm/credentials/workloadIdentityCredential.js +191 -14
  40. package/dist/esm/credentials/workloadIdentityCredential.js.map +1 -1
  41. package/dist/esm/credentials/workloadIdentityCredentialOptions.d.ts +4 -0
  42. package/dist/esm/credentials/workloadIdentityCredentialOptions.d.ts.map +1 -1
  43. package/dist/esm/credentials/workloadIdentityCredentialOptions.js.map +1 -1
  44. package/dist/esm/util/certificatesUtils.d.ts +13 -0
  45. package/dist/esm/util/certificatesUtils.d.ts.map +1 -0
  46. package/dist/esm/util/certificatesUtils.js +47 -0
  47. package/dist/esm/util/certificatesUtils.js.map +1 -0
  48. package/dist/workerd/constants.d.ts +1 -1
  49. package/dist/workerd/constants.d.ts.map +1 -1
  50. package/dist/workerd/constants.js +1 -1
  51. package/dist/workerd/constants.js.map +1 -1
  52. package/dist/workerd/credentials/clientCertificateCredential.d.ts.map +1 -1
  53. package/dist/workerd/credentials/clientCertificateCredential.js +2 -13
  54. package/dist/workerd/credentials/clientCertificateCredential.js.map +1 -1
  55. package/dist/workerd/credentials/workloadIdentityCredential.d.ts +20 -0
  56. package/dist/workerd/credentials/workloadIdentityCredential.d.ts.map +1 -1
  57. package/dist/workerd/credentials/workloadIdentityCredential.js +191 -14
  58. package/dist/workerd/credentials/workloadIdentityCredential.js.map +1 -1
  59. package/dist/workerd/credentials/workloadIdentityCredentialOptions.d.ts +4 -0
  60. package/dist/workerd/credentials/workloadIdentityCredentialOptions.d.ts.map +1 -1
  61. package/dist/workerd/credentials/workloadIdentityCredentialOptions.js.map +1 -1
  62. package/dist/workerd/util/certificatesUtils.d.ts +13 -0
  63. package/dist/workerd/util/certificatesUtils.d.ts.map +1 -0
  64. package/dist/workerd/util/certificatesUtils.js +47 -0
  65. package/dist/workerd/util/certificatesUtils.js.map +1 -0
  66. package/package.json +13 -13
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Current version of the `@azure/identity` package.
3
3
  */
4
- export declare const SDK_VERSION = "4.13.0";
4
+ export declare const SDK_VERSION = "4.14.0-beta.1";
5
5
  /**
6
6
  * The default client ID for authentication
7
7
  * @internal
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,WAAW,WAAW,CAAC;AAEpC;;;GAGG;AAIH,eAAO,MAAM,uBAAuB,yCAAyC,CAAC;AAE9E;;;GAGG;AACH,eAAO,MAAM,eAAe,WAAW,CAAC;AAExC;;GAEG;AACH,oBAAY,mBAAmB;IAC7B;;OAEG;IACH,UAAU,mCAAmC;IAC7C;;;;;SAKK;IACL,YAAY,qCAAqC;IACjD;;OAEG;IACH,eAAe,qCAAqC;IACpD;;OAEG;IACH,gBAAgB,sCAAsC;CACvD;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,uCAAuC,CAAC;AAEzE;;;GAGG;AACH,eAAO,MAAM,gBAAgB,8BAA8B,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,EAAU,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAEtC;;GAEG;AACH,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,eAAe,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,WAAW,kBAAkB,CAAC;AAE3C;;;GAGG;AAIH,eAAO,MAAM,uBAAuB,yCAAyC,CAAC;AAE9E;;;GAGG;AACH,eAAO,MAAM,eAAe,WAAW,CAAC;AAExC;;GAEG;AACH,oBAAY,mBAAmB;IAC7B;;OAEG;IACH,UAAU,mCAAmC;IAC7C;;;;;SAKK;IACL,YAAY,qCAAqC;IACjD;;OAEG;IACH,eAAe,qCAAqC;IACpD;;OAEG;IACH,gBAAgB,sCAAsC;CACvD;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,uCAAuC,CAAC;AAEzE;;;GAGG;AACH,eAAO,MAAM,gBAAgB,8BAA8B,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,EAAU,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAEtC;;GAEG;AACH,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,eAAe,CAAC"}
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  * Current version of the `@azure/identity` package.
5
5
  */
6
- export const SDK_VERSION = `4.13.0`;
6
+ export const SDK_VERSION = `4.14.0-beta.1`;
7
7
  /**
8
8
  * The default client ID for authentication
9
9
  * @internal
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC;AAEpC;;;GAGG;AACH,2EAA2E;AAC3E,6CAA6C;AAC7C,uGAAuG;AACvG,MAAM,CAAC,MAAM,uBAAuB,GAAG,sCAAsC,CAAC;AAE9E;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC;AAExC;;GAEG;AACH,MAAM,CAAN,IAAY,mBAoBX;AApBD,WAAY,mBAAmB;IAC7B;;OAEG;IACH,oEAA6C,CAAA;IAC7C;;;;;SAKK;IACL,wEAAiD,CAAA;IACjD;;OAEG;IACH,2EAAoD,CAAA;IACpD;;OAEG;IACH,6EAAsD,CAAA;AACxD,CAAC,EApBW,mBAAmB,KAAnB,mBAAmB,QAoB9B;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC,gBAAgB,CAAC;AAEzE;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAE5D;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAa,CAAC,GAAG,CAAC,CAAC;AAE3C;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAEtC;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,YAAY,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n/**\n * Current version of the `@azure/identity` package.\n */\nexport const SDK_VERSION = `4.13.0`;\n\n/**\n * The default client ID for authentication\n * @internal\n */\n// TODO: temporary - this is the Azure CLI clientID - we'll replace it when\n// Developer Sign On application is available\n// https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/src/Constants.cs#L9\nexport const DeveloperSignOnClientId = \"04b07795-8ddb-461a-bbee-02f9e1bf7b46\";\n\n/**\n * The default tenant for authentication\n * @internal\n */\nexport const DefaultTenantId = \"common\";\n\n/**\n * A list of known Azure authority hosts\n */\nexport enum AzureAuthorityHosts {\n /**\n * China-based Azure Authority Host\n */\n AzureChina = \"https://login.chinacloudapi.cn\",\n /**\n * Germany-based Azure Authority Host\n *\n * @deprecated Microsoft Cloud Germany was closed on October 29th, 2021.\n *\n * */\n AzureGermany = \"https://login.microsoftonline.de\",\n /**\n * US Government Azure Authority Host\n */\n AzureGovernment = \"https://login.microsoftonline.us\",\n /**\n * Public Cloud Azure Authority Host\n */\n AzurePublicCloud = \"https://login.microsoftonline.com\",\n}\n\n/**\n * @internal\n * The default authority host.\n */\nexport const DefaultAuthorityHost = AzureAuthorityHosts.AzurePublicCloud;\n\n/**\n * @internal\n * The default environment host for Azure Public Cloud\n */\nexport const DefaultAuthority = \"login.microsoftonline.com\";\n\n/**\n * @internal\n * Allow acquiring tokens for any tenant for multi-tentant auth.\n */\nexport const ALL_TENANTS: string[] = [\"*\"];\n\n/**\n * @internal\n */\nexport const CACHE_CAE_SUFFIX = \"cae\";\n\n/**\n * @internal\n */\nexport const CACHE_NON_CAE_SUFFIX = \"nocae\";\n\n/**\n * @internal\n *\n * The default name for the cache persistence plugin.\n * Matches the constant defined in the cache persistence package.\n */\nexport const DEFAULT_TOKEN_CACHE_NAME = \"msal.cache\";\n"]}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,eAAe,CAAC;AAE3C;;;GAGG;AACH,2EAA2E;AAC3E,6CAA6C;AAC7C,uGAAuG;AACvG,MAAM,CAAC,MAAM,uBAAuB,GAAG,sCAAsC,CAAC;AAE9E;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC;AAExC;;GAEG;AACH,MAAM,CAAN,IAAY,mBAoBX;AApBD,WAAY,mBAAmB;IAC7B;;OAEG;IACH,oEAA6C,CAAA;IAC7C;;;;;SAKK;IACL,wEAAiD,CAAA;IACjD;;OAEG;IACH,2EAAoD,CAAA;IACpD;;OAEG;IACH,6EAAsD,CAAA;AACxD,CAAC,EApBW,mBAAmB,KAAnB,mBAAmB,QAoB9B;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC,gBAAgB,CAAC;AAEzE;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAE5D;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAa,CAAC,GAAG,CAAC,CAAC;AAE3C;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAEtC;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,YAAY,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n/**\n * Current version of the `@azure/identity` package.\n */\nexport const SDK_VERSION = `4.14.0-beta.1`;\n\n/**\n * The default client ID for authentication\n * @internal\n */\n// TODO: temporary - this is the Azure CLI clientID - we'll replace it when\n// Developer Sign On application is available\n// https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/src/Constants.cs#L9\nexport const DeveloperSignOnClientId = \"04b07795-8ddb-461a-bbee-02f9e1bf7b46\";\n\n/**\n * The default tenant for authentication\n * @internal\n */\nexport const DefaultTenantId = \"common\";\n\n/**\n * A list of known Azure authority hosts\n */\nexport enum AzureAuthorityHosts {\n /**\n * China-based Azure Authority Host\n */\n AzureChina = \"https://login.chinacloudapi.cn\",\n /**\n * Germany-based Azure Authority Host\n *\n * @deprecated Microsoft Cloud Germany was closed on October 29th, 2021.\n *\n * */\n AzureGermany = \"https://login.microsoftonline.de\",\n /**\n * US Government Azure Authority Host\n */\n AzureGovernment = \"https://login.microsoftonline.us\",\n /**\n * Public Cloud Azure Authority Host\n */\n AzurePublicCloud = \"https://login.microsoftonline.com\",\n}\n\n/**\n * @internal\n * The default authority host.\n */\nexport const DefaultAuthorityHost = AzureAuthorityHosts.AzurePublicCloud;\n\n/**\n * @internal\n * The default environment host for Azure Public Cloud\n */\nexport const DefaultAuthority = \"login.microsoftonline.com\";\n\n/**\n * @internal\n * Allow acquiring tokens for any tenant for multi-tentant auth.\n */\nexport const ALL_TENANTS: string[] = [\"*\"];\n\n/**\n * @internal\n */\nexport const CACHE_CAE_SUFFIX = \"cae\";\n\n/**\n * @internal\n */\nexport const CACHE_NON_CAE_SUFFIX = \"nocae\";\n\n/**\n * @internal\n *\n * The default name for the cache persistence plugin.\n * Matches the constant defined in the cache persistence package.\n */\nexport const DEFAULT_TOKEN_CACHE_NAME = \"msal.cache\";\n"]}
@@ -16,5 +16,9 @@ export interface WorkloadIdentityCredentialOptions extends MultiTenantTokenCrede
16
16
  * The path to a file containing a Kubernetes service account token that authenticates the identity.
17
17
  */
18
18
  tokenFilePath?: string;
19
+ /**
20
+ * Enables the identity binding feature.
21
+ */
22
+ enableAzureKubernetesTokenProxy?: boolean;
19
23
  }
20
24
  //# sourceMappingURL=workloadIdentityCredentialOptions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workloadIdentityCredentialOptions.d.ts","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredentialOptions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAClF,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,wCAAwC,CAAC;AAEhG;;GAEG;AACH,MAAM,WAAW,iCACf,SAAQ,iCAAiC,EACvC,0BAA0B;IAC5B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
1
+ {"version":3,"file":"workloadIdentityCredentialOptions.d.ts","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredentialOptions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAClF,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,wCAAwC,CAAC;AAEhG;;GAEG;AACH,MAAM,WAAW,iCACf,SAAQ,iCAAiC,EACvC,0BAA0B;IAC5B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,+BAA+B,CAAC,EAAE,OAAO,CAAC;CAC3C"}
@@ -1 +1 @@
1
- {"version":3,"file":"workloadIdentityCredentialOptions.js","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredentialOptions.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AuthorityValidationOptions } from \"./authorityValidationOptions.js\";\nimport type { MultiTenantTokenCredentialOptions } from \"./multiTenantTokenCredentialOptions.js\";\n\n/**\n * Options for the {@link WorkloadIdentityCredential}\n */\nexport interface WorkloadIdentityCredentialOptions\n extends MultiTenantTokenCredentialOptions,\n AuthorityValidationOptions {\n /**\n * ID of the application's Microsoft Entra tenant. Also called its directory ID.\n */\n tenantId?: string;\n /**\n * The client ID of a Microsoft Entra app registration.\n */\n clientId?: string;\n /**\n * The path to a file containing a Kubernetes service account token that authenticates the identity.\n */\n tokenFilePath?: string;\n}\n"]}
1
+ {"version":3,"file":"workloadIdentityCredentialOptions.js","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredentialOptions.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AuthorityValidationOptions } from \"./authorityValidationOptions.js\";\nimport type { MultiTenantTokenCredentialOptions } from \"./multiTenantTokenCredentialOptions.js\";\n\n/**\n * Options for the {@link WorkloadIdentityCredential}\n */\nexport interface WorkloadIdentityCredentialOptions\n extends MultiTenantTokenCredentialOptions,\n AuthorityValidationOptions {\n /**\n * ID of the application's Microsoft Entra tenant. Also called its directory ID.\n */\n tenantId?: string;\n /**\n * The client ID of a Microsoft Entra app registration.\n */\n clientId?: string;\n /**\n * The path to a file containing a Kubernetes service account token that authenticates the identity.\n */\n tokenFilePath?: string;\n /**\n * Enables the identity binding feature.\n */\n enableAzureKubernetesTokenProxy?: boolean;\n}\n"]}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Extracts public keys from PEM certificate content
3
+ * @param pemData - The PEM certificate data to parse
4
+ * @returns Array of base64-encoded public key strings
5
+ */
6
+ export declare function extractPemCertificateKeys(pemContent: string): string[];
7
+ /**
8
+ * Checks if PEM certificate content can be parsed as X509Certificate
9
+ * @param pemCert - The PEM certificate
10
+ * @returns true if all certificates in the PEM content can be parsed without error
11
+ */
12
+ export declare function canParseAsX509Certificate(pemCert: string): boolean;
13
+ //# sourceMappingURL=certificatesUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certificatesUtils.d.ts","sourceRoot":"","sources":["../../../src/util/certificatesUtils.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAmBtE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAgBlE"}
@@ -0,0 +1,47 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+ import { X509Certificate } from "crypto";
4
+ /**
5
+ * Extracts public keys from PEM certificate content
6
+ * @param pemData - The PEM certificate data to parse
7
+ * @returns Array of base64-encoded public key strings
8
+ */
9
+ export function extractPemCertificateKeys(pemContent) {
10
+ const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
11
+ const publicKeys = [];
12
+ // Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
13
+ let match;
14
+ do {
15
+ match = certificatePattern.exec(pemContent);
16
+ if (match) {
17
+ publicKeys.push(match[3]);
18
+ }
19
+ } while (match);
20
+ if (publicKeys.length === 0) {
21
+ throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
22
+ }
23
+ return publicKeys;
24
+ }
25
+ /**
26
+ * Checks if PEM certificate content can be parsed as X509Certificate
27
+ * @param pemCert - The PEM certificate
28
+ * @returns true if all certificates in the PEM content can be parsed without error
29
+ */
30
+ export function canParseAsX509Certificate(pemCert) {
31
+ try {
32
+ const pemContents = extractPemCertificateKeys(pemCert);
33
+ for (let i = 0; i < pemContents.length; i++) {
34
+ const pemContent = pemContents[i];
35
+ // Reconstruct the full PEM format for X509Certificate constructor
36
+ const fullPemCertificate = `-----BEGIN CERTIFICATE-----\n${pemContent}\n-----END CERTIFICATE-----`;
37
+ // Attempt to parse as X.509 certificate
38
+ new X509Certificate(fullPemCertificate);
39
+ }
40
+ return true;
41
+ }
42
+ catch (extractError) {
43
+ // Return false for any error (extraction or parsing)
44
+ return false;
45
+ }
46
+ }
47
+ //# sourceMappingURL=certificatesUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certificatesUtils.js","sourceRoot":"","sources":["../../../src/util/certificatesUtils.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAEzC;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,UAAkB;IAC1D,MAAM,kBAAkB,GACtB,+FAA+F,CAAC;IAClG,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,qHAAqH;IACrH,IAAI,KAAK,CAAC;IACV,GAAG,CAAC;QACF,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,KAAK,EAAE,CAAC;YACV,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,QAAQ,KAAK,EAAE;IAEhB,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAe;IACvD,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAC;QAEvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YAClC,kEAAkE;YAClE,MAAM,kBAAkB,GAAG,gCAAgC,UAAU,6BAA6B,CAAC;YACnG,wCAAwC;YACxC,IAAI,eAAe,CAAC,kBAAkB,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,YAAY,EAAE,CAAC;QACtB,qDAAqD;QACrD,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { X509Certificate } from \"crypto\";\n\n/**\n * Extracts public keys from PEM certificate content\n * @param pemData - The PEM certificate data to parse\n * @returns Array of base64-encoded public key strings\n */\nexport function extractPemCertificateKeys(pemContent: string): string[] {\n const certificatePattern =\n /(-+BEGIN CERTIFICATE-+)(\\n\\r?|\\r\\n?)([A-Za-z0-9+/\\n\\r]+=*)(\\n\\r?|\\r\\n?)(-+END CERTIFICATE-+)/g;\n const publicKeys: string[] = [];\n\n // Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c\n let match;\n do {\n match = certificatePattern.exec(pemContent);\n if (match) {\n publicKeys.push(match[3]);\n }\n } while (match);\n\n if (publicKeys.length === 0) {\n throw new Error(\"The file at the specified path does not contain a PEM-encoded certificate.\");\n }\n\n return publicKeys;\n}\n\n/**\n * Checks if PEM certificate content can be parsed as X509Certificate\n * @param pemCert - The PEM certificate\n * @returns true if all certificates in the PEM content can be parsed without error\n */\nexport function canParseAsX509Certificate(pemCert: string): boolean {\n try {\n const pemContents = extractPemCertificateKeys(pemCert);\n\n for (let i = 0; i < pemContents.length; i++) {\n const pemContent = pemContents[i];\n // Reconstruct the full PEM format for X509Certificate constructor\n const fullPemCertificate = `-----BEGIN CERTIFICATE-----\\n${pemContent}\\n-----END CERTIFICATE-----`;\n // Attempt to parse as X.509 certificate\n new X509Certificate(fullPemCertificate);\n }\n return true;\n } catch (extractError) {\n // Return false for any error (extraction or parsing)\n return false;\n }\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Current version of the `@azure/identity` package.
3
3
  */
4
- export declare const SDK_VERSION = "4.13.0";
4
+ export declare const SDK_VERSION = "4.14.0-beta.1";
5
5
  /**
6
6
  * The default client ID for authentication
7
7
  * @internal
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,WAAW,WAAW,CAAC;AAEpC;;;GAGG;AAIH,eAAO,MAAM,uBAAuB,yCAAyC,CAAC;AAE9E;;;GAGG;AACH,eAAO,MAAM,eAAe,WAAW,CAAC;AAExC;;GAEG;AACH,oBAAY,mBAAmB;IAC7B;;OAEG;IACH,UAAU,mCAAmC;IAC7C;;;;;SAKK;IACL,YAAY,qCAAqC;IACjD;;OAEG;IACH,eAAe,qCAAqC;IACpD;;OAEG;IACH,gBAAgB,sCAAsC;CACvD;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,uCAAuC,CAAC;AAEzE;;;GAGG;AACH,eAAO,MAAM,gBAAgB,8BAA8B,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,EAAU,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAEtC;;GAEG;AACH,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,eAAe,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,WAAW,kBAAkB,CAAC;AAE3C;;;GAGG;AAIH,eAAO,MAAM,uBAAuB,yCAAyC,CAAC;AAE9E;;;GAGG;AACH,eAAO,MAAM,eAAe,WAAW,CAAC;AAExC;;GAEG;AACH,oBAAY,mBAAmB;IAC7B;;OAEG;IACH,UAAU,mCAAmC;IAC7C;;;;;SAKK;IACL,YAAY,qCAAqC;IACjD;;OAEG;IACH,eAAe,qCAAqC;IACpD;;OAEG;IACH,gBAAgB,sCAAsC;CACvD;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,uCAAuC,CAAC;AAEzE;;;GAGG;AACH,eAAO,MAAM,gBAAgB,8BAA8B,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,EAAU,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAEtC;;GAEG;AACH,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,eAAe,CAAC"}
@@ -6,7 +6,7 @@ exports.DEFAULT_TOKEN_CACHE_NAME = exports.CACHE_NON_CAE_SUFFIX = exports.CACHE_
6
6
  /**
7
7
  * Current version of the `@azure/identity` package.
8
8
  */
9
- exports.SDK_VERSION = `4.13.0`;
9
+ exports.SDK_VERSION = `4.14.0-beta.1`;
10
10
  /**
11
11
  * The default client ID for authentication
12
12
  * @internal
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC;;;AAElC;;GAEG;AACU,QAAA,WAAW,GAAG,QAAQ,CAAC;AAEpC;;;GAGG;AACH,2EAA2E;AAC3E,6CAA6C;AAC7C,uGAAuG;AAC1F,QAAA,uBAAuB,GAAG,sCAAsC,CAAC;AAE9E;;;GAGG;AACU,QAAA,eAAe,GAAG,QAAQ,CAAC;AAExC;;GAEG;AACH,IAAY,mBAoBX;AApBD,WAAY,mBAAmB;IAC7B;;OAEG;IACH,oEAA6C,CAAA;IAC7C;;;;;SAKK;IACL,wEAAiD,CAAA;IACjD;;OAEG;IACH,2EAAoD,CAAA;IACpD;;OAEG;IACH,6EAAsD,CAAA;AACxD,CAAC,EApBW,mBAAmB,mCAAnB,mBAAmB,QAoB9B;AAED;;;GAGG;AACU,QAAA,oBAAoB,GAAG,mBAAmB,CAAC,gBAAgB,CAAC;AAEzE;;;GAGG;AACU,QAAA,gBAAgB,GAAG,2BAA2B,CAAC;AAE5D;;;GAGG;AACU,QAAA,WAAW,GAAa,CAAC,GAAG,CAAC,CAAC;AAE3C;;GAEG;AACU,QAAA,gBAAgB,GAAG,KAAK,CAAC;AAEtC;;GAEG;AACU,QAAA,oBAAoB,GAAG,OAAO,CAAC;AAE5C;;;;;GAKG;AACU,QAAA,wBAAwB,GAAG,YAAY,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n/**\n * Current version of the `@azure/identity` package.\n */\nexport const SDK_VERSION = `4.13.0`;\n\n/**\n * The default client ID for authentication\n * @internal\n */\n// TODO: temporary - this is the Azure CLI clientID - we'll replace it when\n// Developer Sign On application is available\n// https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/src/Constants.cs#L9\nexport const DeveloperSignOnClientId = \"04b07795-8ddb-461a-bbee-02f9e1bf7b46\";\n\n/**\n * The default tenant for authentication\n * @internal\n */\nexport const DefaultTenantId = \"common\";\n\n/**\n * A list of known Azure authority hosts\n */\nexport enum AzureAuthorityHosts {\n /**\n * China-based Azure Authority Host\n */\n AzureChina = \"https://login.chinacloudapi.cn\",\n /**\n * Germany-based Azure Authority Host\n *\n * @deprecated Microsoft Cloud Germany was closed on October 29th, 2021.\n *\n * */\n AzureGermany = \"https://login.microsoftonline.de\",\n /**\n * US Government Azure Authority Host\n */\n AzureGovernment = \"https://login.microsoftonline.us\",\n /**\n * Public Cloud Azure Authority Host\n */\n AzurePublicCloud = \"https://login.microsoftonline.com\",\n}\n\n/**\n * @internal\n * The default authority host.\n */\nexport const DefaultAuthorityHost = AzureAuthorityHosts.AzurePublicCloud;\n\n/**\n * @internal\n * The default environment host for Azure Public Cloud\n */\nexport const DefaultAuthority = \"login.microsoftonline.com\";\n\n/**\n * @internal\n * Allow acquiring tokens for any tenant for multi-tentant auth.\n */\nexport const ALL_TENANTS: string[] = [\"*\"];\n\n/**\n * @internal\n */\nexport const CACHE_CAE_SUFFIX = \"cae\";\n\n/**\n * @internal\n */\nexport const CACHE_NON_CAE_SUFFIX = \"nocae\";\n\n/**\n * @internal\n *\n * The default name for the cache persistence plugin.\n * Matches the constant defined in the cache persistence package.\n */\nexport const DEFAULT_TOKEN_CACHE_NAME = \"msal.cache\";\n"]}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC;;;AAElC;;GAEG;AACU,QAAA,WAAW,GAAG,eAAe,CAAC;AAE3C;;;GAGG;AACH,2EAA2E;AAC3E,6CAA6C;AAC7C,uGAAuG;AAC1F,QAAA,uBAAuB,GAAG,sCAAsC,CAAC;AAE9E;;;GAGG;AACU,QAAA,eAAe,GAAG,QAAQ,CAAC;AAExC;;GAEG;AACH,IAAY,mBAoBX;AApBD,WAAY,mBAAmB;IAC7B;;OAEG;IACH,oEAA6C,CAAA;IAC7C;;;;;SAKK;IACL,wEAAiD,CAAA;IACjD;;OAEG;IACH,2EAAoD,CAAA;IACpD;;OAEG;IACH,6EAAsD,CAAA;AACxD,CAAC,EApBW,mBAAmB,mCAAnB,mBAAmB,QAoB9B;AAED;;;GAGG;AACU,QAAA,oBAAoB,GAAG,mBAAmB,CAAC,gBAAgB,CAAC;AAEzE;;;GAGG;AACU,QAAA,gBAAgB,GAAG,2BAA2B,CAAC;AAE5D;;;GAGG;AACU,QAAA,WAAW,GAAa,CAAC,GAAG,CAAC,CAAC;AAE3C;;GAEG;AACU,QAAA,gBAAgB,GAAG,KAAK,CAAC;AAEtC;;GAEG;AACU,QAAA,oBAAoB,GAAG,OAAO,CAAC;AAE5C;;;;;GAKG;AACU,QAAA,wBAAwB,GAAG,YAAY,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n/**\n * Current version of the `@azure/identity` package.\n */\nexport const SDK_VERSION = `4.14.0-beta.1`;\n\n/**\n * The default client ID for authentication\n * @internal\n */\n// TODO: temporary - this is the Azure CLI clientID - we'll replace it when\n// Developer Sign On application is available\n// https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/src/Constants.cs#L9\nexport const DeveloperSignOnClientId = \"04b07795-8ddb-461a-bbee-02f9e1bf7b46\";\n\n/**\n * The default tenant for authentication\n * @internal\n */\nexport const DefaultTenantId = \"common\";\n\n/**\n * A list of known Azure authority hosts\n */\nexport enum AzureAuthorityHosts {\n /**\n * China-based Azure Authority Host\n */\n AzureChina = \"https://login.chinacloudapi.cn\",\n /**\n * Germany-based Azure Authority Host\n *\n * @deprecated Microsoft Cloud Germany was closed on October 29th, 2021.\n *\n * */\n AzureGermany = \"https://login.microsoftonline.de\",\n /**\n * US Government Azure Authority Host\n */\n AzureGovernment = \"https://login.microsoftonline.us\",\n /**\n * Public Cloud Azure Authority Host\n */\n AzurePublicCloud = \"https://login.microsoftonline.com\",\n}\n\n/**\n * @internal\n * The default authority host.\n */\nexport const DefaultAuthorityHost = AzureAuthorityHosts.AzurePublicCloud;\n\n/**\n * @internal\n * The default environment host for Azure Public Cloud\n */\nexport const DefaultAuthority = \"login.microsoftonline.com\";\n\n/**\n * @internal\n * Allow acquiring tokens for any tenant for multi-tentant auth.\n */\nexport const ALL_TENANTS: string[] = [\"*\"];\n\n/**\n * @internal\n */\nexport const CACHE_CAE_SUFFIX = \"cae\";\n\n/**\n * @internal\n */\nexport const CACHE_NON_CAE_SUFFIX = \"nocae\";\n\n/**\n * @internal\n *\n * The default name for the cache persistence plugin.\n * Matches the constant defined in the cache persistence package.\n */\nexport const DEFAULT_TOKEN_CACHE_NAME = \"msal.cache\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"clientCertificateCredential.d.ts","sourceRoot":"","sources":["../../../src/credentials/clientCertificateCredential.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAStF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,yCAAyC,CAAC;AAIlG,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAC/B,mCAAmC,EACpC,MAAM,wCAAwC,CAAC;AAKhD;;;;;;;GAOG;AACH,qBAAa,2BAA4B,YAAW,eAAe;IACjE,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,4BAA4B,CAAW;IAC/C,OAAO,CAAC,wBAAwB,CAA8C;IAC9E,OAAO,CAAC,oBAAoB,CAAC,CAAU;IACvC,OAAO,CAAC,UAAU,CAAa;IAE/B;;;;;;;;;OASG;gBAED,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,kCAAkC;IAE9C;;;;;;;;;OASG;gBAED,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,mCAAmC,EAClD,OAAO,CAAC,EAAE,kCAAkC;IAE9C;;;;;;;;;OASG;gBAED,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,+BAA+B,EAC9C,OAAO,CAAC,EAAE,kCAAkC;IA+C9C;;;;;;;OAOG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,WAAW,CAAC;YAehF,sBAAsB;CA6BrC;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,wBAAwB,EAAE,2CAA2C,EACrE,oBAAoB,EAAE,OAAO,GAC5B,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,YAAY,CAAC,GAAG;IAAE,mBAAmB,EAAE,MAAM,CAAA;CAAE,CAAC,CAwCjF"}
1
+ {"version":3,"file":"clientCertificateCredential.d.ts","sourceRoot":"","sources":["../../../src/credentials/clientCertificateCredential.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAStF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,yCAAyC,CAAC;AAIlG,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAC/B,mCAAmC,EACpC,MAAM,wCAAwC,CAAC;AAMhD;;;;;;;GAOG;AACH,qBAAa,2BAA4B,YAAW,eAAe;IACjE,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,4BAA4B,CAAW;IAC/C,OAAO,CAAC,wBAAwB,CAA8C;IAC9E,OAAO,CAAC,oBAAoB,CAAC,CAAU;IACvC,OAAO,CAAC,UAAU,CAAa;IAE/B;;;;;;;;;OASG;gBAED,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,kCAAkC;IAE9C;;;;;;;;;OASG;gBAED,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,mCAAmC,EAClD,OAAO,CAAC,EAAE,kCAAkC;IAE9C;;;;;;;;;OASG;gBAED,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,+BAA+B,EAC9C,OAAO,CAAC,EAAE,kCAAkC;IA+C9C;;;;;;;OAOG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,WAAW,CAAC;YAehF,sBAAsB;CA6BrC;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,wBAAwB,EAAE,2CAA2C,EACrE,oBAAoB,EAAE,OAAO,GAC5B,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,YAAY,CAAC,GAAG;IAAE,mBAAmB,EAAE,MAAM,CAAA;CAAE,CAAC,CAyBjF"}
@@ -10,6 +10,7 @@ const tenantIdUtils_js_1 = require("../util/tenantIdUtils.js");
10
10
  const logging_js_1 = require("../util/logging.js");
11
11
  const promises_1 = require("node:fs/promises");
12
12
  const tracing_js_1 = require("../util/tracing.js");
13
+ const certificatesUtils_js_1 = require("../util/certificatesUtils.js");
13
14
  const credentialName = "ClientCertificateCredential";
14
15
  const logger = (0, logging_js_1.credentialLogger)(credentialName);
15
16
  /**
@@ -112,19 +113,7 @@ async function parseCertificate(certificateConfiguration, sendCertificateChain)
112
113
  .certificatePath;
113
114
  const certificateContents = certificate || (await (0, promises_1.readFile)(certificatePath, "utf8"));
114
115
  const x5c = sendCertificateChain ? certificateContents : undefined;
115
- const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
116
- const publicKeys = [];
117
- // Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
118
- let match;
119
- do {
120
- match = certificatePattern.exec(certificateContents);
121
- if (match) {
122
- publicKeys.push(match[3]);
123
- }
124
- } while (match);
125
- if (publicKeys.length === 0) {
126
- throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
127
- }
116
+ const publicKeys = (0, certificatesUtils_js_1.extractPemCertificateKeys)(certificateContents);
128
117
  const thumbprint = (0, node_crypto_1.createHash)("sha1") // CodeQL [SM04514] Needed for backward compatibility reason
129
118
  .update(Buffer.from(publicKeys[0], "base64"))
130
119
  .digest("hex")
@@ -1 +1 @@
1
- {"version":3,"file":"clientCertificateCredential.js","sourceRoot":"","sources":["../../../src/credentials/clientCertificateCredential.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/core-auth\";\nimport type { MsalClient } from \"../msal/nodeFlows/msalClient.js\";\nimport { createMsalClient } from \"../msal/nodeFlows/msalClient.js\";\nimport { createHash, createPrivateKey } from \"node:crypto\";\nimport {\n processMultiTenantRequest,\n resolveAdditionallyAllowedTenantIds,\n} from \"../util/tenantIdUtils.js\";\n\nimport type { CertificateParts } from \"../msal/types.js\";\nimport type { ClientCertificateCredentialOptions } from \"./clientCertificateCredentialOptions.js\";\nimport { credentialLogger } from \"../util/logging.js\";\nimport { readFile } from \"node:fs/promises\";\nimport { tracingClient } from \"../util/tracing.js\";\nimport type {\n ClientCertificateCredentialPEMConfiguration,\n ClientCertificatePEMCertificate,\n ClientCertificatePEMCertificatePath,\n} from \"./clientCertificateCredentialModels.js\";\n\nconst credentialName = \"ClientCertificateCredential\";\nconst logger = credentialLogger(credentialName);\n\n/**\n * Enables authentication to Microsoft Entra ID using a PEM-encoded\n * certificate that is assigned to an App Registration. More information\n * on how to configure certificate authentication can be found here:\n *\n * https://learn.microsoft.com/azure/active-directory/develop/active-directory-certificate-credentials#register-your-certificate-with-azure-ad\n *\n */\nexport class ClientCertificateCredential implements TokenCredential {\n private tenantId: string;\n private additionallyAllowedTenantIds: string[];\n private certificateConfiguration: ClientCertificateCredentialPEMConfiguration;\n private sendCertificateChain?: boolean;\n private msalClient: MsalClient;\n\n /**\n * Creates an instance of the ClientCertificateCredential with the details\n * needed to authenticate against Microsoft Entra ID with a certificate.\n *\n * @param tenantId - The Microsoft Entra tenant (directory) ID.\n * @param clientId - The client (application) ID of an App Registration in the tenant.\n * @param certificatePath - The path to a PEM-encoded public/private key certificate on the filesystem.\n * Ensure that certificate is in PEM format and contains both the public and private keys.\n * @param options - Options for configuring the client which makes the authentication request.\n */\n constructor(\n tenantId: string,\n clientId: string,\n certificatePath: string,\n options?: ClientCertificateCredentialOptions,\n );\n /**\n * Creates an instance of the ClientCertificateCredential with the details\n * needed to authenticate against Microsoft Entra ID with a certificate.\n *\n * @param tenantId - The Microsoft Entra tenant (directory) ID.\n * @param clientId - The client (application) ID of an App Registration in the tenant.\n * @param configuration - Other parameters required, including the path of the certificate on the filesystem.\n * If the type is ignored, we will throw the value of the path to a PEM certificate.\n * @param options - Options for configuring the client which makes the authentication request.\n */\n constructor(\n tenantId: string,\n clientId: string,\n configuration: ClientCertificatePEMCertificatePath,\n options?: ClientCertificateCredentialOptions,\n );\n /**\n * Creates an instance of the ClientCertificateCredential with the details\n * needed to authenticate against Microsoft Entra ID with a certificate.\n *\n * @param tenantId - The Microsoft Entra tenant (directory) ID.\n * @param clientId - The client (application) ID of an App Registration in the tenant.\n * @param configuration - Other parameters required, including the PEM-encoded certificate as a string.\n * If the type is ignored, we will throw the value of the PEM-encoded certificate.\n * @param options - Options for configuring the client which makes the authentication request.\n */\n constructor(\n tenantId: string,\n clientId: string,\n configuration: ClientCertificatePEMCertificate,\n options?: ClientCertificateCredentialOptions,\n );\n constructor(\n tenantId: string,\n clientId: string,\n certificatePathOrConfiguration: string | ClientCertificateCredentialPEMConfiguration,\n options: ClientCertificateCredentialOptions = {},\n ) {\n if (!tenantId || !clientId) {\n throw new Error(`${credentialName}: tenantId and clientId are required parameters.`);\n }\n\n this.tenantId = tenantId;\n this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(\n options?.additionallyAllowedTenants,\n );\n\n this.sendCertificateChain = options.sendCertificateChain;\n\n this.certificateConfiguration = {\n ...(typeof certificatePathOrConfiguration === \"string\"\n ? {\n certificatePath: certificatePathOrConfiguration,\n }\n : certificatePathOrConfiguration),\n };\n const certificate = (this.certificateConfiguration as ClientCertificatePEMCertificate)\n .certificate;\n const certificatePath = (this.certificateConfiguration as ClientCertificatePEMCertificatePath)\n .certificatePath;\n if (!this.certificateConfiguration || !(certificate || certificatePath)) {\n throw new Error(\n `${credentialName}: Provide either a PEM certificate in string form, or the path to that certificate in the filesystem. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`,\n );\n }\n if (certificate && certificatePath) {\n throw new Error(\n `${credentialName}: To avoid unexpected behaviors, providing both the contents of a PEM certificate and the path to a PEM certificate is forbidden. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`,\n );\n }\n this.msalClient = createMsalClient(clientId, tenantId, {\n ...options,\n logger,\n tokenCredentialOptions: options,\n });\n }\n\n /**\n * Authenticates with Microsoft Entra ID and returns an access token if successful.\n * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.\n *\n * @param scopes - The list of scopes for which the token will have access.\n * @param options - The options used to configure any requests this\n * TokenCredential implementation might make.\n */\n async getToken(scopes: string | string[], options: GetTokenOptions = {}): Promise<AccessToken> {\n return tracingClient.withSpan(`${credentialName}.getToken`, options, async (newOptions) => {\n newOptions.tenantId = processMultiTenantRequest(\n this.tenantId,\n newOptions,\n this.additionallyAllowedTenantIds,\n logger,\n );\n\n const arrayScopes = Array.isArray(scopes) ? scopes : [scopes];\n const certificate = await this.buildClientCertificate();\n return this.msalClient.getTokenByClientCertificate(arrayScopes, certificate, newOptions);\n });\n }\n\n private async buildClientCertificate(): Promise<CertificateParts> {\n const parts = await parseCertificate(\n this.certificateConfiguration,\n this.sendCertificateChain ?? false,\n );\n\n let privateKey: string;\n if (this.certificateConfiguration.certificatePassword !== undefined) {\n privateKey = createPrivateKey({\n key: parts.certificateContents,\n passphrase: this.certificateConfiguration.certificatePassword,\n format: \"pem\",\n })\n .export({\n format: \"pem\",\n type: \"pkcs8\",\n })\n .toString();\n } else {\n privateKey = parts.certificateContents;\n }\n\n return {\n thumbprint: parts.thumbprint,\n thumbprintSha256: parts.thumbprintSha256,\n privateKey,\n x5c: parts.x5c,\n };\n }\n}\n\n/**\n * Parses a certificate into its relevant parts\n *\n * @param certificateConfiguration - The certificate contents or path to the certificate\n * @param sendCertificateChain - true if the entire certificate chain should be sent for SNI, false otherwise\n * @returns The parsed certificate parts and the certificate contents\n */\nexport async function parseCertificate(\n certificateConfiguration: ClientCertificateCredentialPEMConfiguration,\n sendCertificateChain: boolean,\n): Promise<Omit<CertificateParts, \"privateKey\"> & { certificateContents: string }> {\n const certificate = (certificateConfiguration as ClientCertificatePEMCertificate).certificate;\n const certificatePath = (certificateConfiguration as ClientCertificatePEMCertificatePath)\n .certificatePath;\n const certificateContents = certificate || (await readFile(certificatePath!, \"utf8\"));\n const x5c = sendCertificateChain ? certificateContents : undefined;\n\n const certificatePattern =\n /(-+BEGIN CERTIFICATE-+)(\\n\\r?|\\r\\n?)([A-Za-z0-9+/\\n\\r]+=*)(\\n\\r?|\\r\\n?)(-+END CERTIFICATE-+)/g;\n const publicKeys: string[] = [];\n\n // Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c\n let match;\n do {\n match = certificatePattern.exec(certificateContents);\n if (match) {\n publicKeys.push(match[3]);\n }\n } while (match);\n\n if (publicKeys.length === 0) {\n throw new Error(\"The file at the specified path does not contain a PEM-encoded certificate.\");\n }\n\n const thumbprint = createHash(\"sha1\") // CodeQL [SM04514] Needed for backward compatibility reason\n .update(Buffer.from(publicKeys[0], \"base64\"))\n .digest(\"hex\")\n .toUpperCase();\n\n const thumbprintSha256 = createHash(\"sha256\")\n .update(Buffer.from(publicKeys[0], \"base64\"))\n .digest(\"hex\")\n .toUpperCase();\n\n return {\n certificateContents,\n thumbprintSha256,\n thumbprint,\n x5c,\n };\n}\n"]}
1
+ {"version":3,"file":"clientCertificateCredential.js","sourceRoot":"","sources":["../../../src/credentials/clientCertificateCredential.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/core-auth\";\nimport type { MsalClient } from \"../msal/nodeFlows/msalClient.js\";\nimport { createMsalClient } from \"../msal/nodeFlows/msalClient.js\";\nimport { createHash, createPrivateKey } from \"node:crypto\";\nimport {\n processMultiTenantRequest,\n resolveAdditionallyAllowedTenantIds,\n} from \"../util/tenantIdUtils.js\";\n\nimport type { CertificateParts } from \"../msal/types.js\";\nimport type { ClientCertificateCredentialOptions } from \"./clientCertificateCredentialOptions.js\";\nimport { credentialLogger } from \"../util/logging.js\";\nimport { readFile } from \"node:fs/promises\";\nimport { tracingClient } from \"../util/tracing.js\";\nimport type {\n ClientCertificateCredentialPEMConfiguration,\n ClientCertificatePEMCertificate,\n ClientCertificatePEMCertificatePath,\n} from \"./clientCertificateCredentialModels.js\";\nimport { extractPemCertificateKeys } from \"../util/certificatesUtils.js\";\n\nconst credentialName = \"ClientCertificateCredential\";\nconst logger = credentialLogger(credentialName);\n\n/**\n * Enables authentication to Microsoft Entra ID using a PEM-encoded\n * certificate that is assigned to an App Registration. More information\n * on how to configure certificate authentication can be found here:\n *\n * https://learn.microsoft.com/azure/active-directory/develop/active-directory-certificate-credentials#register-your-certificate-with-azure-ad\n *\n */\nexport class ClientCertificateCredential implements TokenCredential {\n private tenantId: string;\n private additionallyAllowedTenantIds: string[];\n private certificateConfiguration: ClientCertificateCredentialPEMConfiguration;\n private sendCertificateChain?: boolean;\n private msalClient: MsalClient;\n\n /**\n * Creates an instance of the ClientCertificateCredential with the details\n * needed to authenticate against Microsoft Entra ID with a certificate.\n *\n * @param tenantId - The Microsoft Entra tenant (directory) ID.\n * @param clientId - The client (application) ID of an App Registration in the tenant.\n * @param certificatePath - The path to a PEM-encoded public/private key certificate on the filesystem.\n * Ensure that certificate is in PEM format and contains both the public and private keys.\n * @param options - Options for configuring the client which makes the authentication request.\n */\n constructor(\n tenantId: string,\n clientId: string,\n certificatePath: string,\n options?: ClientCertificateCredentialOptions,\n );\n /**\n * Creates an instance of the ClientCertificateCredential with the details\n * needed to authenticate against Microsoft Entra ID with a certificate.\n *\n * @param tenantId - The Microsoft Entra tenant (directory) ID.\n * @param clientId - The client (application) ID of an App Registration in the tenant.\n * @param configuration - Other parameters required, including the path of the certificate on the filesystem.\n * If the type is ignored, we will throw the value of the path to a PEM certificate.\n * @param options - Options for configuring the client which makes the authentication request.\n */\n constructor(\n tenantId: string,\n clientId: string,\n configuration: ClientCertificatePEMCertificatePath,\n options?: ClientCertificateCredentialOptions,\n );\n /**\n * Creates an instance of the ClientCertificateCredential with the details\n * needed to authenticate against Microsoft Entra ID with a certificate.\n *\n * @param tenantId - The Microsoft Entra tenant (directory) ID.\n * @param clientId - The client (application) ID of an App Registration in the tenant.\n * @param configuration - Other parameters required, including the PEM-encoded certificate as a string.\n * If the type is ignored, we will throw the value of the PEM-encoded certificate.\n * @param options - Options for configuring the client which makes the authentication request.\n */\n constructor(\n tenantId: string,\n clientId: string,\n configuration: ClientCertificatePEMCertificate,\n options?: ClientCertificateCredentialOptions,\n );\n constructor(\n tenantId: string,\n clientId: string,\n certificatePathOrConfiguration: string | ClientCertificateCredentialPEMConfiguration,\n options: ClientCertificateCredentialOptions = {},\n ) {\n if (!tenantId || !clientId) {\n throw new Error(`${credentialName}: tenantId and clientId are required parameters.`);\n }\n\n this.tenantId = tenantId;\n this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(\n options?.additionallyAllowedTenants,\n );\n\n this.sendCertificateChain = options.sendCertificateChain;\n\n this.certificateConfiguration = {\n ...(typeof certificatePathOrConfiguration === \"string\"\n ? {\n certificatePath: certificatePathOrConfiguration,\n }\n : certificatePathOrConfiguration),\n };\n const certificate = (this.certificateConfiguration as ClientCertificatePEMCertificate)\n .certificate;\n const certificatePath = (this.certificateConfiguration as ClientCertificatePEMCertificatePath)\n .certificatePath;\n if (!this.certificateConfiguration || !(certificate || certificatePath)) {\n throw new Error(\n `${credentialName}: Provide either a PEM certificate in string form, or the path to that certificate in the filesystem. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`,\n );\n }\n if (certificate && certificatePath) {\n throw new Error(\n `${credentialName}: To avoid unexpected behaviors, providing both the contents of a PEM certificate and the path to a PEM certificate is forbidden. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`,\n );\n }\n this.msalClient = createMsalClient(clientId, tenantId, {\n ...options,\n logger,\n tokenCredentialOptions: options,\n });\n }\n\n /**\n * Authenticates with Microsoft Entra ID and returns an access token if successful.\n * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.\n *\n * @param scopes - The list of scopes for which the token will have access.\n * @param options - The options used to configure any requests this\n * TokenCredential implementation might make.\n */\n async getToken(scopes: string | string[], options: GetTokenOptions = {}): Promise<AccessToken> {\n return tracingClient.withSpan(`${credentialName}.getToken`, options, async (newOptions) => {\n newOptions.tenantId = processMultiTenantRequest(\n this.tenantId,\n newOptions,\n this.additionallyAllowedTenantIds,\n logger,\n );\n\n const arrayScopes = Array.isArray(scopes) ? scopes : [scopes];\n const certificate = await this.buildClientCertificate();\n return this.msalClient.getTokenByClientCertificate(arrayScopes, certificate, newOptions);\n });\n }\n\n private async buildClientCertificate(): Promise<CertificateParts> {\n const parts = await parseCertificate(\n this.certificateConfiguration,\n this.sendCertificateChain ?? false,\n );\n\n let privateKey: string;\n if (this.certificateConfiguration.certificatePassword !== undefined) {\n privateKey = createPrivateKey({\n key: parts.certificateContents,\n passphrase: this.certificateConfiguration.certificatePassword,\n format: \"pem\",\n })\n .export({\n format: \"pem\",\n type: \"pkcs8\",\n })\n .toString();\n } else {\n privateKey = parts.certificateContents;\n }\n\n return {\n thumbprint: parts.thumbprint,\n thumbprintSha256: parts.thumbprintSha256,\n privateKey,\n x5c: parts.x5c,\n };\n }\n}\n\n/**\n * Parses a certificate into its relevant parts\n *\n * @param certificateConfiguration - The certificate contents or path to the certificate\n * @param sendCertificateChain - true if the entire certificate chain should be sent for SNI, false otherwise\n * @returns The parsed certificate parts and the certificate contents\n */\nexport async function parseCertificate(\n certificateConfiguration: ClientCertificateCredentialPEMConfiguration,\n sendCertificateChain: boolean,\n): Promise<Omit<CertificateParts, \"privateKey\"> & { certificateContents: string }> {\n const certificate = (certificateConfiguration as ClientCertificatePEMCertificate).certificate;\n const certificatePath = (certificateConfiguration as ClientCertificatePEMCertificatePath)\n .certificatePath;\n const certificateContents = certificate || (await readFile(certificatePath!, \"utf8\"));\n const x5c = sendCertificateChain ? certificateContents : undefined;\n\n const publicKeys = extractPemCertificateKeys(certificateContents);\n\n const thumbprint = createHash(\"sha1\") // CodeQL [SM04514] Needed for backward compatibility reason\n .update(Buffer.from(publicKeys[0], \"base64\"))\n .digest(\"hex\")\n .toUpperCase();\n\n const thumbprintSha256 = createHash(\"sha256\")\n .update(Buffer.from(publicKeys[0], \"base64\"))\n .digest(\"hex\")\n .toUpperCase();\n\n return {\n certificateContents,\n thumbprintSha256,\n thumbprint,\n x5c,\n };\n}\n"]}
@@ -8,6 +8,11 @@ import type { WorkloadIdentityCredentialOptions } from "./workloadIdentityCreden
8
8
  * @internal
9
9
  */
10
10
  export declare const SupportedWorkloadEnvironmentVariables: string[];
11
+ /**
12
+ * @internal
13
+ * Parses and validates the custom token proxy endpoint URL
14
+ */
15
+ export declare function parseAndValidateCustomTokenProxy(endpoint: string): string;
11
16
  /**
12
17
  * Workload Identity authentication is a feature in Azure that allows applications running on virtual machines (VMs)
13
18
  * to access other Azure resources without the need for a service principal or managed identity. With Workload Identity
@@ -27,12 +32,27 @@ export declare class WorkloadIdentityCredential implements TokenCredential {
27
32
  private azureFederatedTokenFileContent;
28
33
  private cacheDate;
29
34
  private federatedTokenFilePath;
35
+ private cachedTlsSettings;
36
+ private cachedCaData;
37
+ private caData;
38
+ private caFile;
39
+ private sniName;
30
40
  /**
31
41
  * WorkloadIdentityCredential supports Microsoft Entra Workload ID on Kubernetes.
32
42
  *
33
43
  * @param options - The identity client options to use for authentication.
34
44
  */
35
45
  constructor(options?: WorkloadIdentityCredentialOptions);
46
+ /**
47
+ * Creates a proxy HttpClient that intercepts token requests and redirects them to the Kubernetes endpoint
48
+ * Caching is handled at the credential level to persist across token requests
49
+ */
50
+ private createAksProxyClient;
51
+ /**
52
+ * Gets TLS settings for the request.
53
+ * Handles a few scenarios with CA data or CA file provided.
54
+ */
55
+ private getTlsSettings;
36
56
  /**
37
57
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
38
58
  * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
@@ -1 +1 @@
1
- {"version":3,"file":"workloadIdentityCredential.d.ts","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredential.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAKtF,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,wCAAwC,CAAC;AAKhG;;;;;;GAMG;AACH,eAAO,MAAM,qCAAqC,UAIjD,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,qBAAa,0BAA2B,YAAW,eAAe;IAChE,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,8BAA8B,CAAiC;IACvE,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,sBAAsB,CAAqB;IAEnD;;;;OAIG;gBACS,OAAO,CAAC,EAAE,iCAAiC;IA6CvD;;;;;;;OAOG;IACU,QAAQ,CACnB,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,EACzB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,WAAW,CAAC;YAcT,gBAAgB;CAwB/B"}
1
+ {"version":3,"file":"workloadIdentityCredential.d.ts","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredential.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAKtF,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,wCAAwC,CAAC;AAUhG;;;;;;GAMG;AACH,eAAO,MAAM,qCAAqC,UAIjD,CAAC;AAwCF;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAwCzE;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,0BAA2B,YAAW,eAAe;IAChE,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,8BAA8B,CAAiC;IACvE,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,sBAAsB,CAAqB;IAGnD,OAAO,CAAC,iBAAiB,CAAsD;IAC/E,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,OAAO,CAAqB;IAEpC;;;;OAIG;gBACS,OAAO,CAAC,EAAE,iCAAiC;IAoFvD;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAqC5B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAiEtB;;;;;;;OAOG;IACU,QAAQ,CACnB,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,EACzB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,WAAW,CAAC;YAUT,gBAAgB;CAwB/B"}
@@ -3,11 +3,15 @@
3
3
  // Licensed under the MIT License.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.WorkloadIdentityCredential = exports.SupportedWorkloadEnvironmentVariables = void 0;
6
+ exports.parseAndValidateCustomTokenProxy = parseAndValidateCustomTokenProxy;
6
7
  const logging_js_1 = require("../util/logging.js");
7
8
  const clientAssertionCredential_js_1 = require("./clientAssertionCredential.js");
8
9
  const errors_js_1 = require("../errors.js");
9
10
  const tenantIdUtils_js_1 = require("../util/tenantIdUtils.js");
10
11
  const promises_1 = require("node:fs/promises");
12
+ const core_rest_pipeline_1 = require("@azure/core-rest-pipeline");
13
+ const certificatesUtils_js_1 = require("../util/certificatesUtils.js");
14
+ const node_fs_1 = require("node:fs");
11
15
  const credentialName = "WorkloadIdentityCredential";
12
16
  /**
13
17
  * Contains the list of all supported environment variable names so that an
@@ -22,6 +26,65 @@ exports.SupportedWorkloadEnvironmentVariables = [
22
26
  "AZURE_FEDERATED_TOKEN_FILE",
23
27
  ];
24
28
  const logger = (0, logging_js_1.credentialLogger)(credentialName);
29
+ /**
30
+ * Error messages for WorkloadIdentityCredential
31
+ */
32
+ const ErrorMessages = {
33
+ FAILED_TO_PARSE_TOKEN_PROXY: (endpoint, error) => `Failed to parse custom token proxy URL "${endpoint}": ${error}`,
34
+ INVALID_HTTPS_SCHEME: (protocol) => `Custom token endpoint must use https scheme, got "${protocol}"`,
35
+ TOKEN_ENDPOINT_NO_USER_INFO: (url) => `Custom token endpoint URL "${url}" must not contain user info`,
36
+ TOKEN_ENDPOINT_NO_QUERY: (url) => `Custom token endpoint URL "${url}" must not contain a query`,
37
+ TOKEN_ENDPOINT_NO_FRAGMENT: (url) => `Custom token endpoint URL "${url}" must not contain a fragment`,
38
+ CA_FILE_EMPTY: (file) => `CA certificate file is empty: ${file}`,
39
+ FAILED_TO_READ_CA_FILE: (file, error) => `Failed to read CA certificate file: ${file}. ${error}`,
40
+ INVALID_CA_CERTIFICATES: `Invalid CA certificate data: no valid PEM certificates found`,
41
+ INVALID_FILE_PATH: (path) => `Invalid file path provided ${path}.`,
42
+ NO_FILE_CONTENT: (path) => `No content on the file ${path}.`,
43
+ NO_CA_SOURCE: `No CA certificate source specified.`,
44
+ CLIENT_ID_REQUIRED: `clientId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_CLIENT_ID".
45
+ See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,
46
+ TENANT_ID_REQUIRED: `tenantId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_TENANT_ID".
47
+ See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,
48
+ TOKEN_FILE_PATH_REQUIRED: `federatedTokenFilePath is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_FEDERATED_TOKEN_FILE".
49
+ See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,
50
+ TOKEN_PROXY_NOT_SET: `AZURE_KUBERNETES_TOKEN_PROXY is not set but other custom endpoint-related environment variables are present`,
51
+ CA_FILE_AND_DATA_EXCLUSIVE: `AZURE_KUBERNETES_CA_FILE and AZURE_KUBERNETES_CA_DATA are mutually exclusive. Specify only one.`,
52
+ MISSING_ENV_VARS: `tenantId, clientId, and federatedTokenFilePath are required parameters.
53
+ In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables -
54
+ "AZURE_TENANT_ID",
55
+ "AZURE_CLIENT_ID",
56
+ "AZURE_FEDERATED_TOKEN_FILE". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,
57
+ };
58
+ /**
59
+ * @internal
60
+ * Parses and validates the custom token proxy endpoint URL
61
+ */
62
+ function parseAndValidateCustomTokenProxy(endpoint) {
63
+ let tokenProxy;
64
+ try {
65
+ tokenProxy = new URL(endpoint);
66
+ }
67
+ catch (error) {
68
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.FAILED_TO_PARSE_TOKEN_PROXY(endpoint, error)}`);
69
+ }
70
+ if (tokenProxy.protocol !== "https:") {
71
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.INVALID_HTTPS_SCHEME(tokenProxy.protocol)}`);
72
+ }
73
+ if (tokenProxy.username || tokenProxy.password) {
74
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_USER_INFO(tokenProxy.toString())}`);
75
+ }
76
+ if (tokenProxy.search) {
77
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_QUERY(tokenProxy.toString())}`);
78
+ }
79
+ if (tokenProxy.hash) {
80
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_FRAGMENT(tokenProxy.toString())}`);
81
+ }
82
+ if (!tokenProxy.pathname || tokenProxy.pathname === "") {
83
+ // if the path is empty, set it to "/" to avoid stripping the path from req.URL
84
+ tokenProxy.pathname = "/";
85
+ }
86
+ return tokenProxy.toString();
87
+ }
25
88
  /**
26
89
  * Workload Identity authentication is a feature in Azure that allows applications running on virtual machines (VMs)
27
90
  * to access other Azure resources without the need for a service principal or managed identity. With Workload Identity
@@ -41,6 +104,12 @@ class WorkloadIdentityCredential {
41
104
  azureFederatedTokenFileContent = undefined;
42
105
  cacheDate = undefined;
43
106
  federatedTokenFilePath;
107
+ // AKS proxy CA caching - persists across token requests
108
+ cachedTlsSettings;
109
+ cachedCaData;
110
+ caData;
111
+ caFile;
112
+ sniName;
44
113
  /**
45
114
  * WorkloadIdentityCredential supports Microsoft Entra Workload ID on Kubernetes.
46
115
  *
@@ -59,19 +128,132 @@ class WorkloadIdentityCredential {
59
128
  (0, tenantIdUtils_js_1.checkTenantId)(logger, tenantId);
60
129
  }
61
130
  if (!clientId) {
62
- throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. clientId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_CLIENT_ID".
63
- See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
131
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.CLIENT_ID_REQUIRED}`);
64
132
  }
65
133
  if (!tenantId) {
66
- throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. tenantId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_TENANT_ID".
67
- See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
134
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TENANT_ID_REQUIRED}`);
68
135
  }
69
136
  if (!this.federatedTokenFilePath) {
70
- throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. federatedTokenFilePath is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_FEDERATED_TOKEN_FILE".
71
- See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
137
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_FILE_PATH_REQUIRED}`);
138
+ }
139
+ // Use identity binding mode only when enableAzureKubernetesTokenProxy is set
140
+ if (workloadIdentityCredentialOptions.enableAzureKubernetesTokenProxy) {
141
+ const kubernetesTokenProxy = process.env.AZURE_KUBERNETES_TOKEN_PROXY;
142
+ const kubernetesSNIName = process.env.AZURE_KUBERNETES_SNI_NAME;
143
+ const kubernetesCAFile = process.env.AZURE_KUBERNETES_CA_FILE;
144
+ const kubernetesCAData = process.env.AZURE_KUBERNETES_CA_DATA;
145
+ if (!kubernetesTokenProxy) {
146
+ // Custom token proxy is not set, while other Kubernetes-related environment variables are present,
147
+ // this is likely a configuration issue so erroring out to avoid misconfiguration
148
+ if (kubernetesSNIName || kubernetesCAFile || kubernetesCAData) {
149
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_PROXY_NOT_SET}`);
150
+ }
151
+ logger.info(`enableAzureKubernetesTokenProxy is true but AZURE_KUBERNETES_TOKEN_PROXY is not set, using normal authentication flow`);
152
+ }
153
+ else {
154
+ const tokenProxy = parseAndValidateCustomTokenProxy(kubernetesTokenProxy);
155
+ // CAFile and CAData are mutually exclusive, at most one can be set.
156
+ // If none of CAFile or CAData are set, the default system CA pool will be used.
157
+ if (kubernetesCAFile && kubernetesCAData) {
158
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.CA_FILE_AND_DATA_EXCLUSIVE}`);
159
+ }
160
+ this.caData = kubernetesCAData;
161
+ this.caFile = kubernetesCAFile;
162
+ this.sniName = kubernetesSNIName;
163
+ // Configure client options with AKS proxy client
164
+ const proxyClient = this.createAksProxyClient(tokenProxy);
165
+ workloadIdentityCredentialOptions.httpClient = proxyClient;
166
+ logger.info(`${credentialName}: Using proxy client for token requests`);
167
+ }
72
168
  }
73
169
  logger.info(`Invoking ClientAssertionCredential with tenant ID: ${tenantId}, clientId: ${workloadIdentityCredentialOptions.clientId} and federated token path: [REDACTED]`);
74
- this.client = new clientAssertionCredential_js_1.ClientAssertionCredential(tenantId, clientId, this.readFileContents.bind(this), options);
170
+ this.client = new clientAssertionCredential_js_1.ClientAssertionCredential(tenantId, clientId, this.readFileContents.bind(this), workloadIdentityCredentialOptions);
171
+ }
172
+ /**
173
+ * Creates a proxy HttpClient that intercepts token requests and redirects them to the Kubernetes endpoint
174
+ * Caching is handled at the credential level to persist across token requests
175
+ */
176
+ createAksProxyClient(tokenEndpoint) {
177
+ const defaultClient = (0, core_rest_pipeline_1.createDefaultHttpClient)();
178
+ // Init cached TLS settings at construction time to fail fast on misconfiguration
179
+ this.cachedTlsSettings = this.getTlsSettings();
180
+ return {
181
+ sendRequest: async (request) => {
182
+ const requestUrl = new URL(request.url);
183
+ logger.info(`${credentialName}: Redirecting request to Kubernetes endpoint: ${tokenEndpoint}`);
184
+ const proxyUrl = new URL(tokenEndpoint);
185
+ // Remove leading slash from request path and join with proxy path
186
+ const requestPath = requestUrl.pathname.replace(/^\//, "");
187
+ const combinedPath = proxyUrl.pathname.endsWith("/")
188
+ ? proxyUrl.pathname + requestPath
189
+ : proxyUrl.pathname + "/" + requestPath;
190
+ // Create new URL preserving query and fragment from original request
191
+ const newUrl = new URL(proxyUrl.origin);
192
+ newUrl.pathname = combinedPath;
193
+ newUrl.search = requestUrl.search;
194
+ newUrl.hash = requestUrl.hash;
195
+ request.url = newUrl.toString();
196
+ request.tlsSettings = this.getTlsSettings();
197
+ logger.info(`${credentialName}: Sending request to ${request.url}`);
198
+ // Forward the modified request with custom TLS settings
199
+ return defaultClient.sendRequest(request);
200
+ },
201
+ };
202
+ }
203
+ /**
204
+ * Gets TLS settings for the request.
205
+ * Handles a few scenarios with CA data or CA file provided.
206
+ */
207
+ getTlsSettings() {
208
+ // No CA overrides, use default transport
209
+ if (!this.caData && !this.caFile) {
210
+ if (!this.cachedTlsSettings) {
211
+ this.cachedTlsSettings = this.sniName ? { servername: this.sniName } : {};
212
+ }
213
+ return this.cachedTlsSettings;
214
+ }
215
+ // Host provided CA bytes in AZURE_KUBERNETES_CA_DATA and can't change now
216
+ if (!this.caFile) {
217
+ if (!this.cachedTlsSettings) {
218
+ if (!(0, certificatesUtils_js_1.canParseAsX509Certificate)(this.caData)) {
219
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.INVALID_CA_CERTIFICATES}`);
220
+ }
221
+ this.cachedTlsSettings = this.sniName ? { servername: this.sniName } : {};
222
+ this.cachedTlsSettings.ca = this.caData;
223
+ }
224
+ return this.cachedTlsSettings;
225
+ }
226
+ // Host provided the CA bytes in a file whose contents it can change,
227
+ let fileContent;
228
+ try {
229
+ fileContent = (0, node_fs_1.readFileSync)(this.caFile);
230
+ }
231
+ catch (error) {
232
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.FAILED_TO_READ_CA_FILE(this.caFile, error)}`);
233
+ }
234
+ // This can happen in the middle of CA rotation
235
+ if (fileContent.length === 0) {
236
+ if (!this.cachedTlsSettings) {
237
+ // If the transport was never created, error out here to force retrying the call later
238
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.CA_FILE_EMPTY(this.caFile)}`);
239
+ }
240
+ // If the transport was already created, just keep using it
241
+ return this.cachedTlsSettings;
242
+ }
243
+ // Check if CA has changed
244
+ if (!this.cachedCaData || !fileContent.equals(this.cachedCaData)) {
245
+ const caDataString = fileContent.toString("utf8");
246
+ if (!(0, certificatesUtils_js_1.canParseAsX509Certificate)(caDataString)) {
247
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.INVALID_CA_CERTIFICATES}`);
248
+ }
249
+ // CA has changed, rebuild the TLS settings with new CA pool
250
+ this.cachedTlsSettings = {
251
+ ca: caDataString,
252
+ ...(this.sniName && { servername: this.sniName }),
253
+ };
254
+ this.cachedCaData = fileContent;
255
+ }
256
+ return this.cachedTlsSettings;
75
257
  }
76
258
  /**
77
259
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
@@ -83,11 +265,7 @@ class WorkloadIdentityCredential {
83
265
  */
84
266
  async getToken(scopes, options) {
85
267
  if (!this.client) {
86
- const errorMessage = `${credentialName}: is unavailable. tenantId, clientId, and federatedTokenFilePath are required parameters.
87
- In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables -
88
- "AZURE_TENANT_ID",
89
- "AZURE_CLIENT_ID",
90
- "AZURE_FEDERATED_TOKEN_FILE". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`;
268
+ const errorMessage = `${credentialName}: is unavailable. ${ErrorMessages.MISSING_ENV_VARS}`;
91
269
  logger.info(errorMessage);
92
270
  throw new errors_js_1.CredentialUnavailableError(errorMessage);
93
271
  }
@@ -100,13 +278,13 @@ class WorkloadIdentityCredential {
100
278
  this.azureFederatedTokenFileContent = undefined;
101
279
  }
102
280
  if (!this.federatedTokenFilePath) {
103
- throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. Invalid file path provided ${this.federatedTokenFilePath}.`);
281
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.INVALID_FILE_PATH(this.federatedTokenFilePath)}`);
104
282
  }
105
283
  if (!this.azureFederatedTokenFileContent) {
106
284
  const file = await (0, promises_1.readFile)(this.federatedTokenFilePath, "utf8");
107
285
  const value = file.trim();
108
286
  if (!value) {
109
- throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. No content on the file ${this.federatedTokenFilePath}.`);
287
+ throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.NO_FILE_CONTENT(this.federatedTokenFilePath)}`);
110
288
  }
111
289
  else {
112
290
  this.azureFederatedTokenFileContent = value;