@azure/identity 4.13.0 → 4.14.0-alpha.20251107.2

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 (89) hide show
  1. package/README.md +1 -1
  2. package/dist/browser/constants.d.ts +1 -1
  3. package/dist/browser/constants.d.ts.map +1 -1
  4. package/dist/browser/constants.js +1 -1
  5. package/dist/browser/constants.js.map +1 -1
  6. package/dist/browser/credentials/chainedTokenCredential.d.ts +1 -1
  7. package/dist/browser/credentials/chainedTokenCredential.js +1 -1
  8. package/dist/browser/credentials/chainedTokenCredential.js.map +1 -1
  9. package/dist/browser/credentials/workloadIdentityCredentialOptions.d.ts +4 -0
  10. package/dist/browser/credentials/workloadIdentityCredentialOptions.d.ts.map +1 -1
  11. package/dist/browser/credentials/workloadIdentityCredentialOptions.js.map +1 -1
  12. package/dist/browser/util/certificatesUtils.d.ts +13 -0
  13. package/dist/browser/util/certificatesUtils.d.ts.map +1 -0
  14. package/dist/browser/util/certificatesUtils.js +47 -0
  15. package/dist/browser/util/certificatesUtils.js.map +1 -0
  16. package/dist/commonjs/constants.d.ts +1 -1
  17. package/dist/commonjs/constants.d.ts.map +1 -1
  18. package/dist/commonjs/constants.js +1 -1
  19. package/dist/commonjs/constants.js.map +1 -1
  20. package/dist/commonjs/credentials/chainedTokenCredential.d.ts +1 -1
  21. package/dist/commonjs/credentials/chainedTokenCredential.js +1 -1
  22. package/dist/commonjs/credentials/chainedTokenCredential.js.map +1 -1
  23. package/dist/commonjs/credentials/clientCertificateCredential.d.ts.map +1 -1
  24. package/dist/commonjs/credentials/clientCertificateCredential.js +2 -13
  25. package/dist/commonjs/credentials/clientCertificateCredential.js.map +1 -1
  26. package/dist/commonjs/credentials/defaultAzureCredential.d.ts +1 -1
  27. package/dist/commonjs/credentials/defaultAzureCredential.js +1 -1
  28. package/dist/commonjs/credentials/defaultAzureCredential.js.map +1 -1
  29. package/dist/commonjs/credentials/workloadIdentityCredential.d.ts +20 -0
  30. package/dist/commonjs/credentials/workloadIdentityCredential.d.ts.map +1 -1
  31. package/dist/commonjs/credentials/workloadIdentityCredential.js +192 -14
  32. package/dist/commonjs/credentials/workloadIdentityCredential.js.map +1 -1
  33. package/dist/commonjs/credentials/workloadIdentityCredentialOptions.d.ts +4 -0
  34. package/dist/commonjs/credentials/workloadIdentityCredentialOptions.d.ts.map +1 -1
  35. package/dist/commonjs/credentials/workloadIdentityCredentialOptions.js.map +1 -1
  36. package/dist/commonjs/tsdoc-metadata.json +1 -1
  37. package/dist/commonjs/util/certificatesUtils.d.ts +13 -0
  38. package/dist/commonjs/util/certificatesUtils.d.ts.map +1 -0
  39. package/dist/commonjs/util/certificatesUtils.js +51 -0
  40. package/dist/commonjs/util/certificatesUtils.js.map +1 -0
  41. package/dist/esm/constants.d.ts +1 -1
  42. package/dist/esm/constants.d.ts.map +1 -1
  43. package/dist/esm/constants.js +1 -1
  44. package/dist/esm/constants.js.map +1 -1
  45. package/dist/esm/credentials/chainedTokenCredential.d.ts +1 -1
  46. package/dist/esm/credentials/chainedTokenCredential.js +1 -1
  47. package/dist/esm/credentials/chainedTokenCredential.js.map +1 -1
  48. package/dist/esm/credentials/clientCertificateCredential.d.ts.map +1 -1
  49. package/dist/esm/credentials/clientCertificateCredential.js +2 -13
  50. package/dist/esm/credentials/clientCertificateCredential.js.map +1 -1
  51. package/dist/esm/credentials/defaultAzureCredential.d.ts +1 -1
  52. package/dist/esm/credentials/defaultAzureCredential.js +1 -1
  53. package/dist/esm/credentials/defaultAzureCredential.js.map +1 -1
  54. package/dist/esm/credentials/workloadIdentityCredential.d.ts +20 -0
  55. package/dist/esm/credentials/workloadIdentityCredential.d.ts.map +1 -1
  56. package/dist/esm/credentials/workloadIdentityCredential.js +191 -14
  57. package/dist/esm/credentials/workloadIdentityCredential.js.map +1 -1
  58. package/dist/esm/credentials/workloadIdentityCredentialOptions.d.ts +4 -0
  59. package/dist/esm/credentials/workloadIdentityCredentialOptions.d.ts.map +1 -1
  60. package/dist/esm/credentials/workloadIdentityCredentialOptions.js.map +1 -1
  61. package/dist/esm/util/certificatesUtils.d.ts +13 -0
  62. package/dist/esm/util/certificatesUtils.d.ts.map +1 -0
  63. package/dist/esm/util/certificatesUtils.js +47 -0
  64. package/dist/esm/util/certificatesUtils.js.map +1 -0
  65. package/dist/workerd/constants.d.ts +1 -1
  66. package/dist/workerd/constants.d.ts.map +1 -1
  67. package/dist/workerd/constants.js +1 -1
  68. package/dist/workerd/constants.js.map +1 -1
  69. package/dist/workerd/credentials/chainedTokenCredential.d.ts +1 -1
  70. package/dist/workerd/credentials/chainedTokenCredential.js +1 -1
  71. package/dist/workerd/credentials/chainedTokenCredential.js.map +1 -1
  72. package/dist/workerd/credentials/clientCertificateCredential.d.ts.map +1 -1
  73. package/dist/workerd/credentials/clientCertificateCredential.js +2 -13
  74. package/dist/workerd/credentials/clientCertificateCredential.js.map +1 -1
  75. package/dist/workerd/credentials/defaultAzureCredential.d.ts +1 -1
  76. package/dist/workerd/credentials/defaultAzureCredential.js +1 -1
  77. package/dist/workerd/credentials/defaultAzureCredential.js.map +1 -1
  78. package/dist/workerd/credentials/workloadIdentityCredential.d.ts +20 -0
  79. package/dist/workerd/credentials/workloadIdentityCredential.d.ts.map +1 -1
  80. package/dist/workerd/credentials/workloadIdentityCredential.js +191 -14
  81. package/dist/workerd/credentials/workloadIdentityCredential.js.map +1 -1
  82. package/dist/workerd/credentials/workloadIdentityCredentialOptions.d.ts +4 -0
  83. package/dist/workerd/credentials/workloadIdentityCredentialOptions.d.ts.map +1 -1
  84. package/dist/workerd/credentials/workloadIdentityCredentialOptions.js.map +1 -1
  85. package/dist/workerd/util/certificatesUtils.d.ts +13 -0
  86. package/dist/workerd/util/certificatesUtils.d.ts.map +1 -0
  87. package/dist/workerd/util/certificatesUtils.js +47 -0
  88. package/dist/workerd/util/certificatesUtils.js.map +1 -0
  89. package/package.json +21 -17
@@ -5,6 +5,9 @@ import { ClientAssertionCredential } from "./clientAssertionCredential.js";
5
5
  import { CredentialUnavailableError } from "../errors.js";
6
6
  import { checkTenantId } from "../util/tenantIdUtils.js";
7
7
  import { readFile } from "node:fs/promises";
8
+ import { createDefaultHttpClient } from "@azure/core-rest-pipeline";
9
+ import { canParseAsX509Certificate } from "../util/certificatesUtils.js";
10
+ import { readFileSync } from "node:fs";
8
11
  const credentialName = "WorkloadIdentityCredential";
9
12
  /**
10
13
  * Contains the list of all supported environment variable names so that an
@@ -19,6 +22,65 @@ export const SupportedWorkloadEnvironmentVariables = [
19
22
  "AZURE_FEDERATED_TOKEN_FILE",
20
23
  ];
21
24
  const logger = credentialLogger(credentialName);
25
+ /**
26
+ * Error messages for WorkloadIdentityCredential
27
+ */
28
+ const ErrorMessages = {
29
+ FAILED_TO_PARSE_TOKEN_PROXY: (endpoint, error) => `Failed to parse custom token proxy URL "${endpoint}": ${error}`,
30
+ INVALID_HTTPS_SCHEME: (protocol) => `Custom token endpoint must use https scheme, got "${protocol}"`,
31
+ TOKEN_ENDPOINT_NO_USER_INFO: (url) => `Custom token endpoint URL "${url}" must not contain user info`,
32
+ TOKEN_ENDPOINT_NO_QUERY: (url) => `Custom token endpoint URL "${url}" must not contain a query`,
33
+ TOKEN_ENDPOINT_NO_FRAGMENT: (url) => `Custom token endpoint URL "${url}" must not contain a fragment`,
34
+ CA_FILE_EMPTY: (file) => `CA certificate file is empty: ${file}`,
35
+ FAILED_TO_READ_CA_FILE: (file, error) => `Failed to read CA certificate file: ${file}. ${error}`,
36
+ INVALID_CA_CERTIFICATES: `Invalid CA certificate data: no valid PEM certificates found`,
37
+ INVALID_FILE_PATH: (path) => `Invalid file path provided ${path}.`,
38
+ NO_FILE_CONTENT: (path) => `No content on the file ${path}.`,
39
+ NO_CA_SOURCE: `No CA certificate source specified.`,
40
+ CLIENT_ID_REQUIRED: `clientId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_CLIENT_ID".
41
+ See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,
42
+ TENANT_ID_REQUIRED: `tenantId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_TENANT_ID".
43
+ See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,
44
+ 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".
45
+ See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,
46
+ TOKEN_PROXY_NOT_SET: `AZURE_KUBERNETES_TOKEN_PROXY is not set but other custom endpoint-related environment variables are present`,
47
+ CA_FILE_AND_DATA_EXCLUSIVE: `AZURE_KUBERNETES_CA_FILE and AZURE_KUBERNETES_CA_DATA are mutually exclusive. Specify only one.`,
48
+ MISSING_ENV_VARS: `tenantId, clientId, and federatedTokenFilePath are required parameters.
49
+ In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables -
50
+ "AZURE_TENANT_ID",
51
+ "AZURE_CLIENT_ID",
52
+ "AZURE_FEDERATED_TOKEN_FILE". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,
53
+ };
54
+ /**
55
+ * @internal
56
+ * Parses and validates the custom token proxy endpoint URL
57
+ */
58
+ export function parseAndValidateCustomTokenProxy(endpoint) {
59
+ let tokenProxy;
60
+ try {
61
+ tokenProxy = new URL(endpoint);
62
+ }
63
+ catch (error) {
64
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.FAILED_TO_PARSE_TOKEN_PROXY(endpoint, error)}`);
65
+ }
66
+ if (tokenProxy.protocol !== "https:") {
67
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.INVALID_HTTPS_SCHEME(tokenProxy.protocol)}`);
68
+ }
69
+ if (tokenProxy.username || tokenProxy.password) {
70
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_USER_INFO(tokenProxy.toString())}`);
71
+ }
72
+ if (tokenProxy.search) {
73
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_QUERY(tokenProxy.toString())}`);
74
+ }
75
+ if (tokenProxy.hash) {
76
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_FRAGMENT(tokenProxy.toString())}`);
77
+ }
78
+ if (!tokenProxy.pathname || tokenProxy.pathname === "") {
79
+ // if the path is empty, set it to "/" to avoid stripping the path from req.URL
80
+ tokenProxy.pathname = "/";
81
+ }
82
+ return tokenProxy.toString();
83
+ }
22
84
  /**
23
85
  * Workload Identity authentication is a feature in Azure that allows applications running on virtual machines (VMs)
24
86
  * to access other Azure resources without the need for a service principal or managed identity. With Workload Identity
@@ -38,6 +100,12 @@ export class WorkloadIdentityCredential {
38
100
  azureFederatedTokenFileContent = undefined;
39
101
  cacheDate = undefined;
40
102
  federatedTokenFilePath;
103
+ // AKS proxy CA caching - persists across token requests
104
+ cachedTlsSettings;
105
+ cachedCaData;
106
+ caData;
107
+ caFile;
108
+ sniName;
41
109
  /**
42
110
  * WorkloadIdentityCredential supports Microsoft Entra Workload ID on Kubernetes.
43
111
  *
@@ -56,19 +124,132 @@ export class WorkloadIdentityCredential {
56
124
  checkTenantId(logger, tenantId);
57
125
  }
58
126
  if (!clientId) {
59
- throw new CredentialUnavailableError(`${credentialName}: is unavailable. clientId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_CLIENT_ID".
60
- See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
127
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.CLIENT_ID_REQUIRED}`);
61
128
  }
62
129
  if (!tenantId) {
63
- throw new CredentialUnavailableError(`${credentialName}: is unavailable. tenantId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_TENANT_ID".
64
- See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
130
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TENANT_ID_REQUIRED}`);
65
131
  }
66
132
  if (!this.federatedTokenFilePath) {
67
- throw new 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".
68
- See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
133
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_FILE_PATH_REQUIRED}`);
134
+ }
135
+ // Use identity binding mode only when enableAzureKubernetesTokenProxy is set
136
+ if (workloadIdentityCredentialOptions.enableAzureKubernetesTokenProxy) {
137
+ const kubernetesTokenProxy = process.env.AZURE_KUBERNETES_TOKEN_PROXY;
138
+ const kubernetesSNIName = process.env.AZURE_KUBERNETES_SNI_NAME;
139
+ const kubernetesCAFile = process.env.AZURE_KUBERNETES_CA_FILE;
140
+ const kubernetesCAData = process.env.AZURE_KUBERNETES_CA_DATA;
141
+ if (!kubernetesTokenProxy) {
142
+ // Custom token proxy is not set, while other Kubernetes-related environment variables are present,
143
+ // this is likely a configuration issue so erroring out to avoid misconfiguration
144
+ if (kubernetesSNIName || kubernetesCAFile || kubernetesCAData) {
145
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_PROXY_NOT_SET}`);
146
+ }
147
+ logger.info(`enableAzureKubernetesTokenProxy is true but AZURE_KUBERNETES_TOKEN_PROXY is not set, using normal authentication flow`);
148
+ }
149
+ else {
150
+ const tokenProxy = parseAndValidateCustomTokenProxy(kubernetesTokenProxy);
151
+ // CAFile and CAData are mutually exclusive, at most one can be set.
152
+ // If none of CAFile or CAData are set, the default system CA pool will be used.
153
+ if (kubernetesCAFile && kubernetesCAData) {
154
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.CA_FILE_AND_DATA_EXCLUSIVE}`);
155
+ }
156
+ this.caData = kubernetesCAData;
157
+ this.caFile = kubernetesCAFile;
158
+ this.sniName = kubernetesSNIName;
159
+ // Configure client options with AKS proxy client
160
+ const proxyClient = this.createAksProxyClient(tokenProxy);
161
+ workloadIdentityCredentialOptions.httpClient = proxyClient;
162
+ logger.info(`${credentialName}: Using proxy client for token requests`);
163
+ }
69
164
  }
70
165
  logger.info(`Invoking ClientAssertionCredential with tenant ID: ${tenantId}, clientId: ${workloadIdentityCredentialOptions.clientId} and federated token path: [REDACTED]`);
71
- this.client = new ClientAssertionCredential(tenantId, clientId, this.readFileContents.bind(this), options);
166
+ this.client = new ClientAssertionCredential(tenantId, clientId, this.readFileContents.bind(this), workloadIdentityCredentialOptions);
167
+ }
168
+ /**
169
+ * Creates a proxy HttpClient that intercepts token requests and redirects them to the Kubernetes endpoint
170
+ * Caching is handled at the credential level to persist across token requests
171
+ */
172
+ createAksProxyClient(tokenEndpoint) {
173
+ const defaultClient = createDefaultHttpClient();
174
+ // Init cached TLS settings at construction time to fail fast on misconfiguration
175
+ this.cachedTlsSettings = this.getTlsSettings();
176
+ return {
177
+ sendRequest: async (request) => {
178
+ const requestUrl = new URL(request.url);
179
+ logger.info(`${credentialName}: Redirecting request to Kubernetes endpoint: ${tokenEndpoint}`);
180
+ const proxyUrl = new URL(tokenEndpoint);
181
+ // Remove leading slash from request path and join with proxy path
182
+ const requestPath = requestUrl.pathname.replace(/^\//, "");
183
+ const combinedPath = proxyUrl.pathname.endsWith("/")
184
+ ? proxyUrl.pathname + requestPath
185
+ : proxyUrl.pathname + "/" + requestPath;
186
+ // Create new URL preserving query and fragment from original request
187
+ const newUrl = new URL(proxyUrl.origin);
188
+ newUrl.pathname = combinedPath;
189
+ newUrl.search = requestUrl.search;
190
+ newUrl.hash = requestUrl.hash;
191
+ request.url = newUrl.toString();
192
+ request.tlsSettings = this.getTlsSettings();
193
+ logger.info(`${credentialName}: Sending request to ${request.url}`);
194
+ // Forward the modified request with custom TLS settings
195
+ return defaultClient.sendRequest(request);
196
+ },
197
+ };
198
+ }
199
+ /**
200
+ * Gets TLS settings for the request.
201
+ * Handles a few scenarios with CA data or CA file provided.
202
+ */
203
+ getTlsSettings() {
204
+ // No CA overrides, use default transport
205
+ if (!this.caData && !this.caFile) {
206
+ if (!this.cachedTlsSettings) {
207
+ this.cachedTlsSettings = this.sniName ? { servername: this.sniName } : {};
208
+ }
209
+ return this.cachedTlsSettings;
210
+ }
211
+ // Host provided CA bytes in AZURE_KUBERNETES_CA_DATA and can't change now
212
+ if (!this.caFile) {
213
+ if (!this.cachedTlsSettings) {
214
+ if (!canParseAsX509Certificate(this.caData)) {
215
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.INVALID_CA_CERTIFICATES}`);
216
+ }
217
+ this.cachedTlsSettings = this.sniName ? { servername: this.sniName } : {};
218
+ this.cachedTlsSettings.ca = this.caData;
219
+ }
220
+ return this.cachedTlsSettings;
221
+ }
222
+ // Host provided the CA bytes in a file whose contents it can change,
223
+ let fileContent;
224
+ try {
225
+ fileContent = readFileSync(this.caFile);
226
+ }
227
+ catch (error) {
228
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.FAILED_TO_READ_CA_FILE(this.caFile, error)}`);
229
+ }
230
+ // This can happen in the middle of CA rotation
231
+ if (fileContent.length === 0) {
232
+ if (!this.cachedTlsSettings) {
233
+ // If the transport was never created, error out here to force retrying the call later
234
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.CA_FILE_EMPTY(this.caFile)}`);
235
+ }
236
+ // If the transport was already created, just keep using it
237
+ return this.cachedTlsSettings;
238
+ }
239
+ // Check if CA has changed
240
+ if (!this.cachedCaData || !fileContent.equals(this.cachedCaData)) {
241
+ const caDataString = fileContent.toString("utf8");
242
+ if (!canParseAsX509Certificate(caDataString)) {
243
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.INVALID_CA_CERTIFICATES}`);
244
+ }
245
+ // CA has changed, rebuild the TLS settings with new CA pool
246
+ this.cachedTlsSettings = {
247
+ ca: caDataString,
248
+ ...(this.sniName && { servername: this.sniName }),
249
+ };
250
+ this.cachedCaData = fileContent;
251
+ }
252
+ return this.cachedTlsSettings;
72
253
  }
73
254
  /**
74
255
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
@@ -80,11 +261,7 @@ export class WorkloadIdentityCredential {
80
261
  */
81
262
  async getToken(scopes, options) {
82
263
  if (!this.client) {
83
- const errorMessage = `${credentialName}: is unavailable. tenantId, clientId, and federatedTokenFilePath are required parameters.
84
- In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables -
85
- "AZURE_TENANT_ID",
86
- "AZURE_CLIENT_ID",
87
- "AZURE_FEDERATED_TOKEN_FILE". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`;
264
+ const errorMessage = `${credentialName}: is unavailable. ${ErrorMessages.MISSING_ENV_VARS}`;
88
265
  logger.info(errorMessage);
89
266
  throw new CredentialUnavailableError(errorMessage);
90
267
  }
@@ -97,13 +274,13 @@ export class WorkloadIdentityCredential {
97
274
  this.azureFederatedTokenFileContent = undefined;
98
275
  }
99
276
  if (!this.federatedTokenFilePath) {
100
- throw new CredentialUnavailableError(`${credentialName}: is unavailable. Invalid file path provided ${this.federatedTokenFilePath}.`);
277
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.INVALID_FILE_PATH(this.federatedTokenFilePath)}`);
101
278
  }
102
279
  if (!this.azureFederatedTokenFileContent) {
103
280
  const file = await readFile(this.federatedTokenFilePath, "utf8");
104
281
  const value = file.trim();
105
282
  if (!value) {
106
- throw new CredentialUnavailableError(`${credentialName}: is unavailable. No content on the file ${this.federatedTokenFilePath}.`);
283
+ throw new CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.NO_FILE_CONTENT(this.federatedTokenFilePath)}`);
107
284
  }
108
285
  else {
109
286
  this.azureFederatedTokenFileContent = value;
@@ -1 +1 @@
1
- {"version":3,"file":"workloadIdentityCredential.js","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredential.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 { credentialLogger, processEnvVars } from \"../util/logging.js\";\n\nimport { ClientAssertionCredential } from \"./clientAssertionCredential.js\";\nimport { CredentialUnavailableError } from \"../errors.js\";\nimport type { WorkloadIdentityCredentialOptions } from \"./workloadIdentityCredentialOptions.js\";\nimport { checkTenantId } from \"../util/tenantIdUtils.js\";\nimport { readFile } from \"node:fs/promises\";\n\nconst credentialName = \"WorkloadIdentityCredential\";\n/**\n * Contains the list of all supported environment variable names so that an\n * appropriate error message can be generated when no credentials can be\n * configured.\n *\n * @internal\n */\nexport const SupportedWorkloadEnvironmentVariables = [\n \"AZURE_TENANT_ID\",\n \"AZURE_CLIENT_ID\",\n \"AZURE_FEDERATED_TOKEN_FILE\",\n];\nconst logger = credentialLogger(credentialName);\n/**\n * Workload Identity authentication is a feature in Azure that allows applications running on virtual machines (VMs)\n * to access other Azure resources without the need for a service principal or managed identity. With Workload Identity\n * authentication, applications authenticate themselves using their own identity, rather than using a shared service\n * principal or managed identity. Under the hood, Workload Identity authentication uses the concept of Service Account\n * Credentials (SACs), which are automatically created by Azure and stored securely in the VM. By using Workload\n * Identity authentication, you can avoid the need to manage and rotate service principals or managed identities for\n * each application on each VM. Additionally, because SACs are created automatically and managed by Azure, you don't\n * need to worry about storing and securing sensitive credentials themselves.\n * The WorkloadIdentityCredential supports Microsoft Entra Workload ID authentication on Azure Kubernetes and acquires\n * a token using the SACs available in the Azure Kubernetes environment.\n * Refer to <a href=\"https://learn.microsoft.com/azure/aks/workload-identity-overview\">Microsoft Entra\n * Workload ID</a> for more information.\n */\nexport class WorkloadIdentityCredential implements TokenCredential {\n private client: ClientAssertionCredential | undefined;\n private azureFederatedTokenFileContent: string | undefined = undefined;\n private cacheDate: number | undefined = undefined;\n private federatedTokenFilePath: string | undefined;\n\n /**\n * WorkloadIdentityCredential supports Microsoft Entra Workload ID on Kubernetes.\n *\n * @param options - The identity client options to use for authentication.\n */\n constructor(options?: WorkloadIdentityCredentialOptions) {\n // Logging environment variables for error details\n const assignedEnv = processEnvVars(SupportedWorkloadEnvironmentVariables).assigned.join(\", \");\n logger.info(`Found the following environment variables: ${assignedEnv}`);\n\n const workloadIdentityCredentialOptions = options ?? {};\n const tenantId = workloadIdentityCredentialOptions.tenantId || process.env.AZURE_TENANT_ID;\n const clientId = workloadIdentityCredentialOptions.clientId || process.env.AZURE_CLIENT_ID;\n this.federatedTokenFilePath =\n workloadIdentityCredentialOptions.tokenFilePath || process.env.AZURE_FEDERATED_TOKEN_FILE;\n if (tenantId) {\n checkTenantId(logger, tenantId);\n }\n if (!clientId) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. clientId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_CLIENT_ID\".\n See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n );\n }\n\n if (!tenantId) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. tenantId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_TENANT_ID\".\n See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n );\n }\n\n if (!this.federatedTokenFilePath) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. federatedTokenFilePath is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_FEDERATED_TOKEN_FILE\".\n See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n );\n }\n\n logger.info(\n `Invoking ClientAssertionCredential with tenant ID: ${tenantId}, clientId: ${workloadIdentityCredentialOptions.clientId} and federated token path: [REDACTED]`,\n );\n this.client = new ClientAssertionCredential(\n tenantId,\n clientId,\n this.readFileContents.bind(this),\n 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 public async getToken(\n scopes: string | string[],\n options?: GetTokenOptions,\n ): Promise<AccessToken> {\n if (!this.client) {\n const errorMessage = `${credentialName}: is unavailable. tenantId, clientId, and federatedTokenFilePath are required parameters. \n In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables - \n \"AZURE_TENANT_ID\",\n \"AZURE_CLIENT_ID\",\n \"AZURE_FEDERATED_TOKEN_FILE\". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`;\n logger.info(errorMessage);\n throw new CredentialUnavailableError(errorMessage);\n }\n logger.info(\"Invoking getToken() of Client Assertion Credential\");\n return this.client.getToken(scopes, options);\n }\n\n private async readFileContents(): Promise<string> {\n // Cached assertions expire after 5 minutes\n if (this.cacheDate !== undefined && Date.now() - this.cacheDate >= 1000 * 60 * 5) {\n this.azureFederatedTokenFileContent = undefined;\n }\n if (!this.federatedTokenFilePath) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. Invalid file path provided ${this.federatedTokenFilePath}.`,\n );\n }\n if (!this.azureFederatedTokenFileContent) {\n const file = await readFile(this.federatedTokenFilePath, \"utf8\");\n const value = file.trim();\n if (!value) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. No content on the file ${this.federatedTokenFilePath}.`,\n );\n } else {\n this.azureFederatedTokenFileContent = value;\n this.cacheDate = Date.now();\n }\n }\n return this.azureFederatedTokenFileContent;\n }\n}\n"]}
1
+ {"version":3,"file":"workloadIdentityCredential.js","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredential.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 { credentialLogger, processEnvVars } from \"../util/logging.js\";\n\nimport { ClientAssertionCredential } from \"./clientAssertionCredential.js\";\nimport { CredentialUnavailableError } from \"../errors.js\";\nimport type { WorkloadIdentityCredentialOptions } from \"./workloadIdentityCredentialOptions.js\";\nimport { checkTenantId } from \"../util/tenantIdUtils.js\";\nimport { readFile } from \"node:fs/promises\";\nimport type { PipelineRequest, PipelineResponse, HttpClient } from \"@azure/core-rest-pipeline\";\nimport { createDefaultHttpClient } from \"@azure/core-rest-pipeline\";\nimport type { TlsSettings } from \"@azure/core-rest-pipeline\";\nimport { canParseAsX509Certificate } from \"../util/certificatesUtils.js\";\nimport { readFileSync } from \"node:fs\";\n\nconst credentialName = \"WorkloadIdentityCredential\";\n/**\n * Contains the list of all supported environment variable names so that an\n * appropriate error message can be generated when no credentials can be\n * configured.\n *\n * @internal\n */\nexport const SupportedWorkloadEnvironmentVariables = [\n \"AZURE_TENANT_ID\",\n \"AZURE_CLIENT_ID\",\n \"AZURE_FEDERATED_TOKEN_FILE\",\n];\n\nconst logger = credentialLogger(credentialName);\n\n/**\n * Error messages for WorkloadIdentityCredential\n */\nconst ErrorMessages = {\n FAILED_TO_PARSE_TOKEN_PROXY: (endpoint: string, error: unknown) =>\n `Failed to parse custom token proxy URL \"${endpoint}\": ${error}`,\n INVALID_HTTPS_SCHEME: (protocol: string) =>\n `Custom token endpoint must use https scheme, got \"${protocol}\"`,\n TOKEN_ENDPOINT_NO_USER_INFO: (url: string) =>\n `Custom token endpoint URL \"${url}\" must not contain user info`,\n TOKEN_ENDPOINT_NO_QUERY: (url: string) =>\n `Custom token endpoint URL \"${url}\" must not contain a query`,\n TOKEN_ENDPOINT_NO_FRAGMENT: (url: string) =>\n `Custom token endpoint URL \"${url}\" must not contain a fragment`,\n CA_FILE_EMPTY: (file: string) => `CA certificate file is empty: ${file}`,\n FAILED_TO_READ_CA_FILE: (file: string, error: unknown) =>\n `Failed to read CA certificate file: ${file}. ${error}`,\n INVALID_CA_CERTIFICATES: `Invalid CA certificate data: no valid PEM certificates found`,\n INVALID_FILE_PATH: (path: string | undefined) => `Invalid file path provided ${path}.`,\n NO_FILE_CONTENT: (path: string) => `No content on the file ${path}.`,\n NO_CA_SOURCE: `No CA certificate source specified.`,\n CLIENT_ID_REQUIRED: `clientId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_CLIENT_ID\".\n See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n TENANT_ID_REQUIRED: `tenantId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_TENANT_ID\".\n See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n 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\".\n See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n TOKEN_PROXY_NOT_SET: `AZURE_KUBERNETES_TOKEN_PROXY is not set but other custom endpoint-related environment variables are present`,\n CA_FILE_AND_DATA_EXCLUSIVE: `AZURE_KUBERNETES_CA_FILE and AZURE_KUBERNETES_CA_DATA are mutually exclusive. Specify only one.`,\n MISSING_ENV_VARS: `tenantId, clientId, and federatedTokenFilePath are required parameters. \n In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables - \n \"AZURE_TENANT_ID\",\n \"AZURE_CLIENT_ID\",\n \"AZURE_FEDERATED_TOKEN_FILE\". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n};\n\n/**\n * @internal\n * Parses and validates the custom token proxy endpoint URL\n */\nexport function parseAndValidateCustomTokenProxy(endpoint: string): string {\n let tokenProxy: URL;\n try {\n tokenProxy = new URL(endpoint);\n } catch (error) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.FAILED_TO_PARSE_TOKEN_PROXY(endpoint, error)}`,\n );\n }\n\n if (tokenProxy.protocol !== \"https:\") {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.INVALID_HTTPS_SCHEME(tokenProxy.protocol)}`,\n );\n }\n\n if (tokenProxy.username || tokenProxy.password) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_USER_INFO(tokenProxy.toString())}`,\n );\n }\n\n if (tokenProxy.search) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_QUERY(tokenProxy.toString())}`,\n );\n }\n\n if (tokenProxy.hash) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_FRAGMENT(tokenProxy.toString())}`,\n );\n }\n\n if (!tokenProxy.pathname || tokenProxy.pathname === \"\") {\n // if the path is empty, set it to \"/\" to avoid stripping the path from req.URL\n tokenProxy.pathname = \"/\";\n }\n\n return tokenProxy.toString();\n}\n\n/**\n * Workload Identity authentication is a feature in Azure that allows applications running on virtual machines (VMs)\n * to access other Azure resources without the need for a service principal or managed identity. With Workload Identity\n * authentication, applications authenticate themselves using their own identity, rather than using a shared service\n * principal or managed identity. Under the hood, Workload Identity authentication uses the concept of Service Account\n * Credentials (SACs), which are automatically created by Azure and stored securely in the VM. By using Workload\n * Identity authentication, you can avoid the need to manage and rotate service principals or managed identities for\n * each application on each VM. Additionally, because SACs are created automatically and managed by Azure, you don't\n * need to worry about storing and securing sensitive credentials themselves.\n * The WorkloadIdentityCredential supports Microsoft Entra Workload ID authentication on Azure Kubernetes and acquires\n * a token using the SACs available in the Azure Kubernetes environment.\n * Refer to <a href=\"https://learn.microsoft.com/azure/aks/workload-identity-overview\">Microsoft Entra\n * Workload ID</a> for more information.\n */\nexport class WorkloadIdentityCredential implements TokenCredential {\n private client: ClientAssertionCredential | undefined;\n private azureFederatedTokenFileContent: string | undefined = undefined;\n private cacheDate: number | undefined = undefined;\n private federatedTokenFilePath: string | undefined;\n\n // AKS proxy CA caching - persists across token requests\n private cachedTlsSettings: (TlsSettings & { servername?: string }) | undefined;\n private cachedCaData: Buffer | undefined;\n private caData: string | undefined;\n private caFile: string | undefined;\n private sniName: string | undefined;\n\n /**\n * WorkloadIdentityCredential supports Microsoft Entra Workload ID on Kubernetes.\n *\n * @param options - The identity client options to use for authentication.\n */\n constructor(options?: WorkloadIdentityCredentialOptions) {\n // Logging environment variables for error details\n const assignedEnv = processEnvVars(SupportedWorkloadEnvironmentVariables).assigned.join(\", \");\n logger.info(`Found the following environment variables: ${assignedEnv}`);\n\n const workloadIdentityCredentialOptions = options ?? {};\n const tenantId = workloadIdentityCredentialOptions.tenantId || process.env.AZURE_TENANT_ID;\n const clientId = workloadIdentityCredentialOptions.clientId || process.env.AZURE_CLIENT_ID;\n this.federatedTokenFilePath =\n workloadIdentityCredentialOptions.tokenFilePath || process.env.AZURE_FEDERATED_TOKEN_FILE;\n\n if (tenantId) {\n checkTenantId(logger, tenantId);\n }\n if (!clientId) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.CLIENT_ID_REQUIRED}`,\n );\n }\n\n if (!tenantId) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.TENANT_ID_REQUIRED}`,\n );\n }\n\n if (!this.federatedTokenFilePath) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.TOKEN_FILE_PATH_REQUIRED}`,\n );\n }\n\n // Use identity binding mode only when enableAzureKubernetesTokenProxy is set\n if (workloadIdentityCredentialOptions.enableAzureKubernetesTokenProxy) {\n const kubernetesTokenProxy = process.env.AZURE_KUBERNETES_TOKEN_PROXY;\n const kubernetesSNIName = process.env.AZURE_KUBERNETES_SNI_NAME;\n const kubernetesCAFile = process.env.AZURE_KUBERNETES_CA_FILE;\n const kubernetesCAData = process.env.AZURE_KUBERNETES_CA_DATA;\n\n if (!kubernetesTokenProxy) {\n // Custom token proxy is not set, while other Kubernetes-related environment variables are present,\n // this is likely a configuration issue so erroring out to avoid misconfiguration\n if (kubernetesSNIName || kubernetesCAFile || kubernetesCAData) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.TOKEN_PROXY_NOT_SET}`,\n );\n }\n logger.info(\n `enableAzureKubernetesTokenProxy is true but AZURE_KUBERNETES_TOKEN_PROXY is not set, using normal authentication flow`,\n );\n } else {\n const tokenProxy = parseAndValidateCustomTokenProxy(kubernetesTokenProxy);\n\n // CAFile and CAData are mutually exclusive, at most one can be set.\n // If none of CAFile or CAData are set, the default system CA pool will be used.\n if (kubernetesCAFile && kubernetesCAData) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.CA_FILE_AND_DATA_EXCLUSIVE}`,\n );\n }\n\n this.caData = kubernetesCAData;\n this.caFile = kubernetesCAFile;\n this.sniName = kubernetesSNIName;\n\n // Configure client options with AKS proxy client\n const proxyClient = this.createAksProxyClient(tokenProxy);\n workloadIdentityCredentialOptions.httpClient = proxyClient;\n logger.info(`${credentialName}: Using proxy client for token requests`);\n }\n }\n\n logger.info(\n `Invoking ClientAssertionCredential with tenant ID: ${tenantId}, clientId: ${workloadIdentityCredentialOptions.clientId} and federated token path: [REDACTED]`,\n );\n\n this.client = new ClientAssertionCredential(\n tenantId,\n clientId,\n this.readFileContents.bind(this),\n workloadIdentityCredentialOptions,\n );\n }\n\n /**\n * Creates a proxy HttpClient that intercepts token requests and redirects them to the Kubernetes endpoint\n * Caching is handled at the credential level to persist across token requests\n */\n private createAksProxyClient(tokenEndpoint: string): HttpClient {\n const defaultClient = createDefaultHttpClient();\n // Init cached TLS settings at construction time to fail fast on misconfiguration\n this.cachedTlsSettings = this.getTlsSettings();\n\n return {\n sendRequest: async (request: PipelineRequest): Promise<PipelineResponse> => {\n const requestUrl = new URL(request.url);\n\n logger.info(\n `${credentialName}: Redirecting request to Kubernetes endpoint: ${tokenEndpoint}`,\n );\n\n const proxyUrl = new URL(tokenEndpoint);\n\n // Remove leading slash from request path and join with proxy path\n const requestPath = requestUrl.pathname.replace(/^\\//, \"\");\n const combinedPath = proxyUrl.pathname.endsWith(\"/\")\n ? proxyUrl.pathname + requestPath\n : proxyUrl.pathname + \"/\" + requestPath;\n\n // Create new URL preserving query and fragment from original request\n const newUrl = new URL(proxyUrl.origin);\n newUrl.pathname = combinedPath;\n newUrl.search = requestUrl.search;\n newUrl.hash = requestUrl.hash;\n\n request.url = newUrl.toString();\n request.tlsSettings = this.getTlsSettings();\n\n logger.info(`${credentialName}: Sending request to ${request.url}`);\n // Forward the modified request with custom TLS settings\n return defaultClient.sendRequest(request);\n },\n };\n }\n\n /**\n * Gets TLS settings for the request.\n * Handles a few scenarios with CA data or CA file provided.\n */\n private getTlsSettings(): TlsSettings & { servername?: string } {\n // No CA overrides, use default transport\n if (!this.caData && !this.caFile) {\n if (!this.cachedTlsSettings) {\n this.cachedTlsSettings = this.sniName ? { servername: this.sniName } : {};\n }\n return this.cachedTlsSettings;\n }\n\n // Host provided CA bytes in AZURE_KUBERNETES_CA_DATA and can't change now\n if (!this.caFile) {\n if (!this.cachedTlsSettings) {\n if (!canParseAsX509Certificate(this.caData!)) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.INVALID_CA_CERTIFICATES}`,\n );\n }\n this.cachedTlsSettings = this.sniName ? { servername: this.sniName } : {};\n this.cachedTlsSettings.ca = this.caData;\n }\n return this.cachedTlsSettings;\n }\n\n // Host provided the CA bytes in a file whose contents it can change,\n let fileContent: Buffer;\n try {\n fileContent = readFileSync(this.caFile);\n } catch (error) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.FAILED_TO_READ_CA_FILE(this.caFile!, error)}`,\n );\n }\n // This can happen in the middle of CA rotation\n if (fileContent.length === 0) {\n if (!this.cachedTlsSettings) {\n // If the transport was never created, error out here to force retrying the call later\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.CA_FILE_EMPTY(this.caFile)}`,\n );\n }\n // If the transport was already created, just keep using it\n return this.cachedTlsSettings;\n }\n\n // Check if CA has changed\n if (!this.cachedCaData || !fileContent.equals(this.cachedCaData)) {\n const caDataString = fileContent.toString(\"utf8\");\n\n if (!canParseAsX509Certificate(caDataString)) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.INVALID_CA_CERTIFICATES}`,\n );\n }\n\n // CA has changed, rebuild the TLS settings with new CA pool\n this.cachedTlsSettings = {\n ca: caDataString,\n ...(this.sniName && { servername: this.sniName }),\n };\n this.cachedCaData = fileContent;\n }\n\n return this.cachedTlsSettings!;\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 public async getToken(\n scopes: string | string[],\n options?: GetTokenOptions,\n ): Promise<AccessToken> {\n if (!this.client) {\n const errorMessage = `${credentialName}: is unavailable. ${ErrorMessages.MISSING_ENV_VARS}`;\n logger.info(errorMessage);\n throw new CredentialUnavailableError(errorMessage);\n }\n logger.info(\"Invoking getToken() of Client Assertion Credential\");\n return this.client.getToken(scopes, options);\n }\n\n private async readFileContents(): Promise<string> {\n // Cached assertions expire after 5 minutes\n if (this.cacheDate !== undefined && Date.now() - this.cacheDate >= 1000 * 60 * 5) {\n this.azureFederatedTokenFileContent = undefined;\n }\n if (!this.federatedTokenFilePath) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.INVALID_FILE_PATH(this.federatedTokenFilePath)}`,\n );\n }\n if (!this.azureFederatedTokenFileContent) {\n const file = await readFile(this.federatedTokenFilePath, \"utf8\");\n const value = file.trim();\n if (!value) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.NO_FILE_CONTENT(this.federatedTokenFilePath)}`,\n );\n } else {\n this.azureFederatedTokenFileContent = value;\n this.cacheDate = Date.now();\n }\n }\n return this.azureFederatedTokenFileContent;\n }\n}\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"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@azure/identity",
3
3
  "sdk-type": "client",
4
- "version": "4.13.0",
4
+ "version": "4.14.0-alpha.20251107.2",
5
5
  "description": "Provides credential implementations for Azure SDK libraries that can authenticate with Microsoft Entra ID",
6
6
  "main": "./dist/commonjs/index.js",
7
7
  "module": "./dist/esm/index.js",
@@ -57,13 +57,13 @@
57
57
  "homepage": "https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity/README.md",
58
58
  "sideEffects": false,
59
59
  "dependencies": {
60
- "@azure/abort-controller": "^2.0.0",
61
- "@azure/core-auth": "^1.9.0",
62
- "@azure/core-client": "^1.9.2",
63
- "@azure/core-rest-pipeline": "^1.17.0",
64
- "@azure/core-tracing": "^1.0.0",
65
- "@azure/core-util": "^1.11.0",
66
- "@azure/logger": "^1.0.0",
60
+ "@azure/abort-controller": ">=2.1.3-alpha <2.1.3-alphb",
61
+ "@azure/core-auth": ">=1.10.2-alpha <1.10.2-alphb",
62
+ "@azure/core-client": ">=1.10.2-alpha <1.10.2-alphb",
63
+ "@azure/core-rest-pipeline": ">=1.22.2-alpha <1.22.2-alphb",
64
+ "@azure/core-tracing": ">=1.3.2-alpha <1.3.2-alphb",
65
+ "@azure/core-util": ">=1.13.2-alpha <1.13.2-alphb",
66
+ "@azure/logger": ">=1.3.1-alpha <1.3.1-alphb",
67
67
  "@azure/msal-browser": "^4.2.0",
68
68
  "@azure/msal-node": "^3.5.0",
69
69
  "open": "^10.1.0",
@@ -74,20 +74,24 @@
74
74
  "@types/jsonwebtoken": "^9.0.0",
75
75
  "@types/ms": "^2.1.0",
76
76
  "@types/node": "^20.19.0",
77
- "@vitest/browser": "^3.2.3",
78
- "@vitest/coverage-istanbul": "^3.2.3",
77
+ "@vitest/browser-playwright": "^4.0.0",
78
+ "@vitest/coverage-istanbul": "^4.0.6",
79
79
  "assertion-error": "^2.0.1",
80
+ "cross-env": "^7.0.3",
80
81
  "dotenv": "^16.0.0",
81
82
  "eslint": "^9.33.0",
82
83
  "jsonwebtoken": "^9.0.0",
83
84
  "ms": "^2.1.3",
84
85
  "playwright": "^1.50.1",
85
- "typescript": "~5.8.3",
86
- "vitest": "^3.2.3",
87
- "@azure-tools/test-recorder": "^4.1.1",
86
+ "prettier": "^3.6.2",
87
+ "rimraf": "^6.0.1",
88
+ "tshy": "^3.0.0",
89
+ "typescript": "~5.9.3",
90
+ "vitest": "^4.0.6",
88
91
  "@azure-tools/test-utils-vitest": "^2.0.1",
89
92
  "@azure/dev-tool": "^1.0.0",
90
- "@azure/eslint-plugin-azure-sdk": "^3.0.0"
93
+ "@azure/eslint-plugin-azure-sdk": "^3.0.0",
94
+ "@azure-tools/test-recorder": "^4.1.1"
91
95
  },
92
96
  "type": "module",
93
97
  "tshy": {
@@ -130,11 +134,11 @@
130
134
  "scripts": {
131
135
  "build": "npm run clean && dev-tool run build-package && dev-tool run extract-api",
132
136
  "build:samples": "tsc -p tsconfig.samples.json",
133
- "check-format": "dev-tool run vendored prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
134
- "clean": "dev-tool run vendored rimraf --glob dist dist-* types *.tgz *.log",
137
+ "check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
138
+ "clean": "rimraf --glob dist dist-* types *.tgz *.log",
135
139
  "execute:samples": "dev-tool samples run samples-dev",
136
140
  "extract-api": "dev-tool run build-package && dev-tool run extract-api",
137
- "format": "dev-tool run vendored prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
141
+ "format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
138
142
  "lint": "eslint package.json src test --ignore-pattern 'test/integration/**'",
139
143
  "lint:fix": "eslint package.json src test --fix --fix-type [problem,suggestion] --ignore-pattern 'test/integration/**'",
140
144
  "pack": "pnpm pack 2>&1",